Lecture W5T1: State Machines, and the Lab 3 Launch
September 22, 2026
LECTURE W5T1 // STATE OF PLAY
match, and exactly one door.Housekeeping: Lab 3 is due Thursday, October 1, 9:59 PM. The team repo link assignment is due today; if your team has not submitted, do it during studio.
2 minutes with your teammate:
Today’s demos live in a new repo, rival-brains: one arena, Blitz, and one rival. Follow along or just watch; every demo is a branch you can check out later.
project.godot in Godot.git checkout demo1, then run the project.You cannot lose the ghost. It never rests, never patrols, never gives up. It has no moods, because it has no brain. Just one urge, forever.
On branch demo1, in rival.gd. This is all of it:
Ten lines, and it works. It is also done growing. Watch what happens when we ask for more.
var is_patrolling := true and an if around the chase.var is_frightened := false and var fear_timer := 0.0, and now the patrol if needs and not is_frightened, and so does the chase…Implicit state. Your booleans are states, just unnamed and unguarded. Eight flags means 256 possible combinations, and you designed maybe six of them. The other 250 are bugs waiting for a playtester to find.
The cure is to stop letting states happen by accident and start declaring them.
A finite state machine is a brain with rooms: a fixed set of named states; the machine is in exactly one at a time; each state owns its own rules (what happens here) and its own exits (when and where to leave); and every state change is an explicit, deliberate event.
This is GPP: State, this week’s reading, and it is the oldest reliable brain in games.
A state machine fits on an index card. The rival we want:
| From | When | To |
|---|---|---|
| PATROL | Blitz closer than the sight range | CHASE |
| CHASE | Blitz farther than the give-up range | PATROL |
The two separate thresholds are deliberate: sight at 260, give-up at 360. With a single threshold the rival would flicker between moods right at the line. The gap is called hysteresis, and every good chase AI has it.
If you cannot draw this table, the brain is still flag soup. Sketch one for your project’s enemies too.
On branch demo2, rival.gd starts with two lines that change everything:
The heart of rival.gd on demo2:
match state:
State.PATROL:
var target := patrol_points[patrol_index]
if global_position.distance_to(target) < 12.0:
patrol_index = (patrol_index + 1) % patrol_points.size()
target = patrol_points[patrol_index]
velocity = (target - global_position).normalized() * patrol_speed
if to_player.length() < sight_range:
_change_state(State.CHASE)
State.CHASE:
velocity = to_player.normalized() * chase_speed
if to_player.length() > give_up_range:
_change_state(State.PATROL)Each room owns its movement and its exits, and nothing else. PATROL knows nothing about chasing. CHASE has never heard of waypoints.
Every transition goes through one function, in rival.gd:
git checkout demo2 (accept Godot’s reload prompt; settings never change between branches).Same ghost, ten more minutes of work, an actual personality. Rules live in rooms; effects live in the door; the table we drew is exactly the code we wrote.
Lab 3: Platformer. The rival’s brain pattern, turned sideways: a Bearcat who runs, jumps, dies on spikes, and plants a flag. You get the level geometry and three Bearcat poses free. You build the body, then you build the brain.
| Milestone | What exists after it |
|---|---|
| M1 | A body with gravity: run, jump from the floor |
| M2 | The brain transplant: enum + match + one door, same behavior |
| M3 | States you can see: each state wears its own pose |
| M4 | The world pushes back: spikes respawn you, the flag declares CLEAR |
| M5 | Make it yours: at least one twist, and the best twists are new states |
Due Thursday, October 1, 9:59 PM. Push to main at every milestone; pushing is the submission. The README’s requirements are the contract: custom actions, an explicit state machine with one transition function, visible states, a world that pushes back, named layers with a written layer map, one custom feature, class code style.
The M5 menu leans into new states: a dash, a wall slide, coyote time. That is deliberate. The lab is not really about platforms; it is about rooms and doors, and your project’s controllers are next.
Rest of class. In order:
GUIDE.md and build M1. Aim to have a Bearcat jumping on platforms before you leave this room.match, and one _change_state door that owns every entry effect (demo2’s tint included).Lab 3: Platformer is due Thursday, October 1, 9:59 PM: pushed to main, Your Submission section complete.
Team repo link is due today if your team has not submitted it yet.
Reading (highly recommended, short): GPP: State. You now have the scars to appreciate it.
Thursday: the rival’s brain grows. The fig forces FRIGHTENED from outside (demo3), the game itself becomes a machine with title and game-over screens (demo4), and your teams get sprint time. The proposal gate (Thursday, October 8) is on the horizon.
The lab calendar has shifted to protect your project runway. The syllabus is updated (v1.0), and the Canvas home page matches:
demo1 through demo4, one brain upgrade each.GUIDE.md, milestones M1 through M5.