Games and Programming in the Wild

Make Your Own Game


Learning Objectives

  • You can choose a game small enough to actually finish.
  • You can identify the state and the per-frame rules a game needs before writing code.
  • You can build a game by starting with the smallest playable version and adding one feature at a time.
  • You can map a game idea back to the techniques from the eight games you built.

This chapter is the capstone for the part. There is no new game to type, no new technique to learn. Instead, you are going to make a game of your own — and the job of this chapter is to give you a way of doing that which actually leads to a finished game rather than an abandoned one.

You have followed how to build eight small games. The way to consolidate everything this part taught is to build a ninth that is yours: a game nobody handed you the code for, that you designed and finished. It does not need to be original or impressive. It needs to be small, playable, and done.

The Single Most Important Decision: Make It Small

The most common way a first game fails is not a bug. It is ambition. “A role-playing game with a world to explore and characters to talk to” is a project that defeats experienced developers; as a first solo game it is a guaranteed way to end up with a folder of unfinished code and a sour feeling.

The games in this part are the right size. Each one fits in a single file, has one core mechanic, and can be played in under a minute. Your game should be the same. A good rule: describe your whole game in one sentence, and if the sentence needs the word “and” more than once, the game is too big. “Dodge the falling rocks” is a game. “Dodge the falling rocks and collect coins and fight a boss and level up” is four games, none of which will get finished.

Finishing a tiny game teaches you more than not-finishing a big one. A complete game, however small, forces you to handle the parts that beginners skip: the start, the end, the restart, the moment of winning or losing. Those unglamorous edges are where most of the real learning is, and a small game is the only kind where you will reach them.

A Framework for Designing the Game

Before writing any code, answer four questions on paper:

What is the state? List every piece of information the game needs to remember. The player’s position. The score. The list of enemies. The fuel. This is the set of instance variables your App will hold, and naming them now — before any code — is the single most clarifying thing you can do. Every game in this part began as a short list of state.

What happens each frame? Describe what update does, in plain sentences. “Move the player by the arrow keys. Move each enemy down. If any enemy touches the player, the game ends.” This is the rule of the game, and writing it as sentences first means the code becomes a translation rather than an invention.

How does the player win or lose? Name the end conditions explicitly. “You win when the score reaches 100.” “You lose when you run out of fuel.” These become the conditions that flip your game into its end state.

What does a frame look like? Sketch the screen — literally, on paper. What is drawn, and where. This becomes your draw method, and sketching it stops you from discovering halfway through that you never decided what the enemies look like.

Four answers, and you have designed a game. The code is now mostly transcription.

Build the Smallest Playable Version First

Do not build the whole game and run it at the end. Build the smallest thing that runs, then grow it one feature at a time, running it after each addition. This is the most important working habit in the chapter.

Concretely, for almost any game, the growth order is:

  1. A window that opens and clears. The skeleton from the game-loop chapter, nothing else. Run it. A black window is a victory — it means Pyxel is working and your structure is sound.
  2. One thing on screen that you control. Draw the player and move it with the keys. Run it. Now you have something to look at.
  3. One thing it interacts with. An enemy, a wall, a ball — and the collision or rule between them. Run it. Now it is arguably a game.
  4. The win and lose conditions. The end state and the restart. Run it. Now it is finishably a game.
  5. Polish, one piece at a time. A score display, a second enemy, a title screen. Run it after each.

The discipline is the “run it” after every step. When something breaks, you know it was the last thing you added, because everything before it was working. Adding one feature at a time and testing each is the difference between debugging one new change and debugging an entire untested program at once — it adapts the one-step-at-a-time habit from From Rows to Records to a whole game.

Borrow From the Games You Built

Your game does not need techniques you have not seen. Whatever genre you pick, one of the eight games has the core of it, and you should go back and reread that chapter’s code:

If your game involves…Look at…for…
A number that growsIdle Clickerstate as a few variables, timers
Things that move and driftAsteroidsvelocity, lists of objects, wrapping
BouncingBreakoutreflection, paddle clamp, brick lists
A grid that follows rulesConway’s Life2D grids, build-new-not-edit-in-place
A level you walk throughMazetile maps, grid-vs-pixel coords, walls
Shooting, many enemiesGalagatwo lists, safe removal, formations
Gravity, weight, momentumLunar Landeracceleration, fuel, two-part win check
Turns, puzzles, undo2048turn-based state, snapshots, undo

Most games combine two or three of these. A platformer is the Lunar Lander’s gravity plus the Maze’s tile collisions. A tower-defence game is the Galaga’s enemy lists plus the Idle Clicker’s resource economy. Seeing your idea as a combination of techniques you already have is what makes “make your own game” achievable rather than daunting.

Using AI on Your Own Game

This is the natural place to put the whole AI thread to work, the last skill especially. A good workflow:

Specify the mechanic precisely, the way the previous chapter described — state, timing, rule, edge cases, constraints, and a check — and ask for that one piece, not the whole game. “I have a player dict with x and y; write the update code so it falls under gravity and the up arrow thrusts, burning fuel.” A narrow, well-specified request gets code you can actually check.

Then verify it against Pyxel itself, not against the assistant’s confidence: suspect any unfamiliar function call, watch for AttributeError as a version-or-typo signal, and confirm against the documentation, dir(pyxel), or a tiny test. And read what comes back the way the whole course has trained you to — understanding each line, not pasting it and hoping.

An AI assistant is genuinely useful here, especially for the fiddly bits like collision maths or the transpose trick. But the game is yours, which means the judgement is yours: you decide what it should do, you check that the code does it, and you own the result.

Some Starting Points

If you want a prompt rather than a blank page, any of these is small enough to finish in a sitting:

  • Falling dodge. Rocks fall from the top; move left and right to avoid them; survive as long as you can. (Asteroids’ lists, no wrapping, one direction of movement.)
  • Snake. A growing line of segments on a grid; eat food to grow; lose if you hit yourself. (Maze’s grid plus a list that grows.)
  • Flappy clone. One button to flap against gravity; pipes scroll past; squeeze through the gaps. (Lunar Lander’s gravity plus moving obstacles.)
  • Memory match. A grid of hidden tiles; flip two; keep them if they match. (2048’s grid plus turn-based state.)
  • Whack-a-mole. Targets pop up at random grid positions on a timer; click them before they vanish. (The clicker’s timer plus the maze’s grid, plus mouse input — the one technique the chapters did not use. Pyxel offers pyxel.mouse_x, pyxel.mouse_y, and pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT); checking them against the documentation before trusting them is exactly the library habit this part has been practising.)

Pick one, answer the four design questions for it, build the smallest playable version, and grow it. Then — and this is the real end of the part — play it, and show it to someone. A finished game, however small, that another person can pick up and play, is the thing this whole part was building toward.


When You Get Stuck

Every game-in-progress hits a wall: a bug you cannot find, a mechanic that will not feel right. Two moves almost always help. First, make it smaller — comment out half the game and get the remaining half working perfectly, then add back one piece. A bug in a small program is a bug you can find. Second, add a pyxel.text that prints the value you are unsure about straight onto the screen — the player’s velocity, the length of a list, the current state string. Seeing the number every frame turns “I don’t know why it does that” into “oh, the velocity is negative when it shouldn’t be.” Both moves are the debugging instincts from earlier parts, in a setting where the program is changing thirty times a second.


Make your own game

0 / 40 points

Create a small Pyxel game of your own in the online editor.

You may choose any game idea and organize the code with functions, classes, or a mixture of both. Keep it small enough to finish and make sure someone else can play it. Your submitted game must have this runnable core:

  • importing your submitted program must be safe and must not open a window or start the game loop,
  • running your submitted program must call pyxel.init(...) and pyxel.run(update, draw), with callable update and draw callbacks,
  • the update callback must query player input with pyxel.btn(...), pyxel.btnp(...), or pyxel.btnr(...),
  • the draw callback must clear the screen with pyxel.cls(...) and draw something visible with a Pyxel drawing function such as text, pset, line, rect, rectb, circ, circb, elli, ellib, tri, trib, blt, or bltm,
  • game state must change over time or in response to input,
  • and the game must have a clear win, loss, score, goal, or other measure of progress.

Put the launch behind an if __name__ == "__main__": guard. For a class-based game, the guard may create your app object. For a function-based game, it may call a setup function. The automated check does not require particular class, function, or variable names.

Because this game is your own, you decide the rules. Before the imports, add a leading rules block with at least three non-placeholder comment lines. Across those lines, explain:

  • the goal of the game,
  • the controls,
  • how the player wins, loses, scores points, or measures progress,
  • which objects move or change each frame,
  • and any important edge cases, such as what happens at walls, when a resource runs out, or when the game ends.

Start from the smallest playable version and add one feature at a time. You may borrow mechanics from any game in this part: movement, bouncing, grids, shooting, gravity, timers, undo, collisions, or anything else you can explain and finish.

If you use AI, ask for one small mechanic at a time. Describe the state, timing, rule, and edge cases, and check any unfamiliar Pyxel calls against the documentation or a tiny test.

This remains an open-ended project. The automated check verifies the three-line rules block and the design-neutral import, launch, callback, input-query, and drawing requirements above. It cannot decide whether the state changes meaningfully, the game is enjoyable, or the implementation fully matches the rules you wrote. Run and play the game yourself before submitting it.

AI Study Aid

Create a chapter diagram

We're looking into to what extent AI-generated diagrams could help with studying.

Use this study aid to generate an AI-generated visual summary of the material you just studied. Each diagram style emphasizes the content in a different way, so you can choose the focus that feels most useful.

Using the diagram generator is voluntary and does not affect your course progress. We encourage you to try it out and see if it helps, but it's totally up to you! Your answers help us understand how to make better study aids in the future.

Diagrams tried: 0