Stage 05 — The Enemy Thinks
You will build: a slime that idles, spots you, chases, telegraphs, attacks, and gets stunned by your hits — composed from the components you already own, plus its own brain. You'll learn: enemy AI state machines · telegraph design — and design decision 2 (AI style) gets made on real code. Warm-up — from memory:
- The full damage chain, hitbox to
died, from yesterday's out-loud test. - Which decision did you record for knockback, and what did the losing option cost?
Why this exists#
An enemy is a state machine wearing your components. The states are the genre's grammar — IDLE (hasn't seen you) · CHASE (has) · WINDUP (about to hurt you, visibly) · ATTACK (hurting) · STUNNED (you interrupted it). The one that makes fast combat fair is WINDUP: a readable pause before every attack is the contract that lets players dodge on reaction. Skip it and your game is cheap; stretch it and your game is easy — tuning that window is enemy design in one number.
Build it#
A — Decision 2, decided by building#
The architecture offers enum-FSM (your player's style) vs node-based (one child node per
state). The honest way to choose is to feel both: sketch the slime's brain as an enum
match first — you know this pattern cold — then convert IDLE and CHASE to node-states and
notice what got better or worse. Keep whichever you'd rather add a sixth state to. Record
the choice, the reason, and one sentence about what the comparison taught you.
B — The slime#
enemies/slime.tscn: CharacterBody2D (layer enemy, mask world) · sprite · your
Hurtbox + Health, unchanged · a DetectionArea (Area2D masking player) · its own
Hitbox (layer enemy_hit) for the lunge · @export var stats: EnemyStats — make that
Resource now (speed, health, detection radius, windup time), and let it drive the nodes
(set shape radii and health from stats in _ready; a .tres should be the whole
difference between slime variants).
C — The brain, state by state#
- IDLE → CHASE: DetectionArea sees the player. (Signal or poll? You've earned an opinion — use it, defend it.)
- CHASE:
move_towardthe player atstats.speed— with acceleration, so the slime has weight too. Within lunge range → WINDUP. - WINDUP: stop dead, telegraph loudly — squash the sprite, tint it, anything — for
stats.windup_time. This stillness is the player's reaction window; start at 0.4s. - ATTACK: the lunge — a short burst of velocity with the hitbox active (sound familiar? it's your dash wearing a hitbox — reuse the thinking, not just code). Then a brief recovery → CHASE.
- STUNNED: entered when its Hurtbox reports damage; knockback per your decision-1 mechanism, a beat of helplessness, back to CHASE. Interrupting a WINDUP with a hit should feel great — if it doesn't, your stun duration is telling you something.
D — The fight#
One slime in the arena. Fight it for ten minutes. Tune: detection radius, windup, lunge speed, stun duration. Then instance three — does the fight stay fair, or do simultaneous lunges need... no, don't fix it yet. Write down what breaks; that's the next-module list writing itself.
git add . && git commit -m "stage 05: slime AI — chase, telegraph, lunge, stun"
Checkpoint — definition of done#
- The full loop reads at a glance: you can see what the slime intends before it acts
- A sword hit during WINDUP cancels into STUNNED — interrupts work and feel earned
- Dash-through-lunge takes no damage; getting caught flat does
- A second slime variant exists as a
.tresonly — faster, frailer, twitchier — and demonstrably behaves differently - Decision 2 recorded, with the comparison sentence
- Zero warnings; committed. Explain: why does WINDUP exist from the player's chair, not the programmer's?
Stretch (no instructions)#
Wander: IDLE drifts lazily instead of standing frozen. Watch how much more alive the arena feels for ~15 lines.
If you get stuck#
- Slime vibrates against the player → it's overshooting its stop distance every frame;
compare distance-check against where
move_towardwill actually put it. - Never leaves IDLE → the DetectionArea chain again: layers, masks, signal, radius — print at each link, find the silent one (the stage-04 technique, paying rent already).
- Stun-lock: you can juggle it forever → is that a bug or your game's identity? Decision 3 territory — either way, make it a choice, written down.