doc 7 of 9

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:

  1. The full damage chain, hitbox to died, from yesterday's out-loud test.
  2. 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_toward the player at stats.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 .tres only — 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_toward will 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.