Applied Module 12 · The Lora Playbook

The Enemy Behavior Sandbox

What you'll learn

~60 min
  • Generate a Phaser 3 combat room with multiple enemy types and configurable AI
  • Implement a finite state machine for enemy behavior with six states
  • Tune enemy aggression, pursuit, and attack patterns with real-time sliders
  • Build three distinct enemy archetypes: melee grunt, ranged soldier, and boss

What you’re building

The combat prototype gave you one enemy that patrols and punches. BloodRayne had dozens of enemy types — soldiers with rifles, supernatural creatures that lunged from shadows, and bosses that demanded pattern recognition and patience. The enemies are what make combat interesting. A perfect combo system is meaningless if the enemies just walk back and forth waiting to die.

In this lesson you are building an enemy behavior sandbox — a Phaser 3 combat room with three enemy types, each running a finite state machine with tunable parameters. A side panel lets you adjust aggression, pursuit distance, attack cooldowns, and more in real time. You will use this sandbox to design enemies that force the player to use every tool from Lesson 10: combos for the grunts, dodges for the ranged shots, and pattern reading for the boss.

Software pattern: Finite state machine for autonomous agents

A finite state machine (FSM) is one of the most widely used patterns in software: an entity can be in exactly one state at a time, and transitions between states are triggered by conditions. In games, enemy AI uses FSMs. In business software, order processing uses FSMs (pending, approved, shipped, delivered). The same mental model applies — states, transitions, and conditions.


The showcase

Here is what the finished sandbox gives you:

  • Combat room with floor, platforms, and three enemy types active simultaneously
  • Player character (Rayne) with combat controls from Lesson 10
  • Melee Grunt (green) — state machine: idle, patrol, alert, chase, attack, hurt, dead
  • Ranged Soldier (purple) — state machine: idle, patrol, alert, retreat, shoot, hurt, dead
  • Boss (large red) — state machine: idle, approach, telegraph, heavy attack, summon, enrage, hurt, dead
  • Tuning panel with tabs for each enemy type, containing sliders for:
    • Detection range (how far they “see” the player)
    • Pursuit speed (how fast they chase)
    • Attack cooldown (time between attacks)
    • Attack damage
    • Aggression (0-100%, affects how quickly they transition from passive to aggressive states)
    • Telegraph duration (how long the warning animation plays before attacking)
    • Health
  • State indicator above each enemy showing their current FSM state in small text
  • Spawn controls — buttons to add or remove each enemy type from the room

The prompt

Open your terminal, navigate to your project folder, start your AI CLI tool, and paste this prompt:

Build a Phaser 3 enemy behavior sandbox for a BloodRayne-inspired side-scrolling
action game. The sandbox has three configurable enemy types with finite state
machine AI, plus a tuning panel for real-time parameter adjustment.
PROJECT STRUCTURE:
enemy-behavior-sandbox/
index.html (Phaser 3 game + HTML tuning panel, all inline)
SPECIFICATIONS:
1. PAGE LAYOUT
- Split layout: game canvas on left (680px wide), tuning panel on right (300px)
- Tuning panel has three tabs at the top: "Grunt", "Ranged", "Boss"
- Each tab shows sliders for that enemy type's parameters
- Dark panel background (#1a1a2e), light text, styled range inputs
- Spawn buttons at the bottom: "Add Grunt", "Add Ranged", "Add Boss",
"Clear All"
2. GAME SCENE (680x450 canvas)
- Background: dark dungeon aesthetic (dark gray gradient)
- Ground floor full width, two elevated platforms (left-high, right-mid)
- Player (Rayne): 32x48 dark red rectangle, same controls as combat prototype:
arrow keys to move, Z for 3-hit combo attack, X for dodge roll with i-frames
- Player has 150 HP with a health bar at top-left
- Enemies spawn from the right side
3. MELEE GRUNT (green rectangle, 28x44)
Finite state machine with these states:
IDLE: Stand still for 1-3 seconds. Transition to PATROL after timer.
PATROL: Walk back and forth in a 150px range at 60px/s.
Transition to ALERT if player is within detectionRange.
ALERT: Stop moving, flash yellow exclamation mark above head for 0.5s.
Transition to CHASE after alert animation.
CHASE: Move toward player at pursuitSpeed. Transition to ATTACK when
within 45px. Transition to PATROL if player moves beyond detectionRange * 1.5
(hysteresis to prevent flickering).
ATTACK: Stop. Telegraph by flashing yellow for telegraphDuration ms.
Then deal attackDamage to player if still in range (45px). Enter cooldown.
Transition to CHASE after cooldown expires.
HURT: Flash white, knockback 80px away from damage source. 300ms stagger.
Transition to CHASE when stagger ends (or DEAD if HP <= 0).
DEAD: Play death animation (shrink + fade over 500ms). Remove from scene.
If "auto-respawn" is checked in panel, respawn after 4 seconds.
Default tunable values:
- detectionRange: 220px
- pursuitSpeed: 130px/s
- attackCooldown: 1200ms
- attackDamage: 12
- telegraphDuration: 350ms
- health: 80
- aggression: 50 (affects: at 100%, skip ALERT state and go straight to
CHASE; at 0%, stay in PATROL even when player is close for up to 2 extra seconds)
4. RANGED SOLDIER (purple rectangle, 24x40)
Finite state machine:
IDLE: Stand still briefly. Transition to PATROL.
PATROL: Walk back and forth at 50px/s in a 180px range.
Transition to ALERT if player within detectionRange.
ALERT: Stop, flash yellow for 0.4s. Transition to RETREAT or SHOOT
based on distance.
RETREAT: If player is within 120px, move away from player at 100px/s
until preferred range (200-280px) is reached. Then transition to SHOOT.
SHOOT: Stand still. Telegraph by raising arm (small rectangle extends
upward) for telegraphDuration ms. Fire a projectile (small yellow circle,
8px diameter) at projectileSpeed toward player's current position.
Projectile deals attackDamage on hit. Enter cooldown, transition to IDLE.
If player closes distance below 120px during cooldown, transition to RETREAT.
HURT: Same as grunt (flash white, knockback, stagger).
DEAD: Same as grunt (shrink, fade, optional respawn).
Projectile: travels in a straight line, destroyed on hit or after 3 seconds.
Player can dodge through projectiles with i-frames.
Default tunable values:
- detectionRange: 320px
- pursuitSpeed: 100px/s (retreat speed)
- attackCooldown: 2000ms
- attackDamage: 15
- projectileSpeed: 280px/s
- telegraphDuration: 400ms
- health: 60
- aggression: 40
5. BOSS (large dark red rectangle, 48x64)
Finite state machine:
IDLE: Stand center-right of arena. Transition to APPROACH when player
enters detectionRange.
APPROACH: Walk toward player at pursuitSpeed. Transition to TELEGRAPH
when within 80px.
TELEGRAPH: Flash bright red and grow slightly (scale 1.1x) for
telegraphDuration ms. Shows a red danger zone on the ground indicating
attack area. Transition to HEAVY_ATTACK.
HEAVY_ATTACK: Slam attack dealing attackDamage in a 100px radius around
the boss. Screen shake on impact. Particles scatter. 30 damage default.
Transition to SUMMON or APPROACH based on a cooldown cycle.
SUMMON: Every third attack cycle, instead of approaching again, pause
for 1 second and spawn one melee grunt. Max 2 summoned grunts alive
at a time. Transition to APPROACH after summon.
ENRAGE: When health drops below 30%, permanently increase pursuitSpeed
by 50%, reduce attackCooldown by 30%, and tint the boss sprite bright
red. Flash "ENRAGED" text. This transition happens once.
HURT: Flash white, minimal knockback (boss is heavy -- only 30px).
500ms stagger. Transition to APPROACH (or ENRAGE if health threshold crossed).
DEAD: Dramatic death -- screen freeze 200ms, large particle explosion,
"BOSS DEFEATED" text center screen. Does not respawn.
Default tunable values:
- detectionRange: 350px
- pursuitSpeed: 80px/s
- attackCooldown: 2500ms
- attackDamage: 30
- telegraphDuration: 700ms
- health: 300
- aggression: 60
- enrageThreshold: 30 (percent HP)
6. TUNING PANEL
Each enemy tab has sliders that update in real time:
- Detection Range: range varies per type, step 10
- Pursuit Speed: range 30-300, step 10
- Attack Cooldown: range 500-4000, step 100
- Attack Damage: range 5-50, step 5
- Telegraph Duration: range 100-1500, step 50
- Health: range 20-500, step 10
- Aggression: range 0-100, step 5
- (Ranged only) Projectile Speed: range 100-500, step 20
- (Boss only) Enrage Threshold: range 10-80, step 5
Changes apply to newly spawned enemies AND update existing enemies
of that type in real time.
Preset buttons per type:
- "Cannon Fodder" -- low HP, low damage, low aggression (easy grunt)
- "Dangerous" -- high pursuit speed, high aggression, short telegraphs
- "BloodRayne Classic" -- balanced for action game feel
- "Reset" -- back to defaults
7. STATE DEBUG DISPLAY
- Above each enemy, show current state in small white text:
"IDLE", "PATROL", "ALERT", "CHASE", "ATTACK", "SHOOT", "RETREAT", etc.
- This text updates in real time as states transition
- Toggle on/off with a checkbox in the panel labeled "Show AI States"
8. VISUAL FEEDBACK
- Telegraph animations are critical -- the player MUST be able to see
the attack coming and react. Make telegraphs obvious: color flash +
ground indicator for boss slam, arm raise for ranged shot.
- Projectiles leave a faint trail (3 semi-transparent copies behind)
- Hit particles on all damage events (same as combat prototype)
- Screen shake on boss heavy attack
- Kill counter in top-right: "Grunts: 3 | Soldiers: 1 | Boss: 0"
TECHNICAL: Phaser 3 from CDN, Arcade physics, colored rectangles only, runs
by opening index.html. The tuning panel communicates with the game through
a shared window.enemyConfig object with grunt, ranged, and boss sub-objects.
💡Copy-paste ready

That prompt is long because enemy AI has more moving parts than player movement. Each state machine has six to eight states, each with transition conditions and tunable values. The specificity ensures you get enemies that actually behave differently — a grunt that charges, a soldier that kites, and a boss that demands respect. Vague enemy prompts produce enemies that all walk toward you and punch.


What you get

After the AI finishes:

enemy-behavior-sandbox/
index.html

Play it

Terminal window
cd enemy-behavior-sandbox
open index.html

Click “Add Grunt” a couple of times. Watch them patrol. Walk into their detection range and watch the exclamation mark flash before they chase. Attack them and watch the HURT state stagger. Now add a Ranged Soldier — notice how it backs away when you get close. Add the Boss. Respect the telegraph.

If something is off

ProblemFollow-up prompt
Enemies all do the same thingThe enemy types are not differentiated. Each type needs its own state machine class or configuration. The grunt should chase and melee, the ranged soldier should retreat and shoot projectiles, and the boss should telegraph heavy slams and summon grunts. Make sure each enemy type reads from its own config sub-object (window.enemyConfig.grunt, .ranged, .boss).
State transitions are instant — no telegraph visibleThe telegraph state is too fast or being skipped. Make sure the TELEGRAPH state sets a timer (this.scene.time.delayedCall(telegraphDuration, ...)) and the enemy does NOT deal damage until that timer completes. During the telegraph, the enemy should flash yellow (grunt/ranged) or red (boss) using a tint tween.
Ranged soldier doesn’t retreatThe ranged soldier never enters RETREAT state. Add a distance check in update: if player is within 120px AND the soldier is in IDLE/SHOOT/ALERT state, transition to RETREAT. In RETREAT, set velocity away from the player until distance exceeds 200px, then transition to SHOOT.
Boss enrage never triggersThe ENRAGE state is not being checked. In the HURT state handler, after reducing HP, check if health <= maxHealth * (enrageThreshold / 100) AND a boolean hasEnraged is false. If so, set hasEnraged to true, increase pursuitSpeed by 50%, reduce attackCooldown by 30%, apply red tint, and show "ENRAGED" text.

Deep dive

Why telegraphs are non-negotiable

A telegraph is the visual warning before an enemy attacks. The grunt flashes yellow. The boss flashes red and shows a ground indicator. Without telegraphs, attacks feel unfair — the player cannot react to something they cannot see coming. With telegraphs, attacks become a conversation: the enemy says “I’m about to hit you” and the player says “I dodge” or “I counter-attack.” Every great action game uses telegraphs. Dark Souls bosses wind up for a full second. Hades enemies flash before lunging. BloodRayne enemies had distinct pre-attack animations. Your telegraph duration slider lets you find the right balance between “readable” and “challenging.”

The aggression slider changes the game

Aggression is a meta-parameter that affects how quickly enemies escalate from passive to hostile. At 0% aggression, grunts linger in PATROL even when they see you — they give you time. At 100%, they skip the ALERT state entirely and sprint at you the moment you enter detection range. This single slider transforms the same enemy from a training dummy into a threat. In the final game, you might set early-level grunts to 30% aggression and late-level grunts to 80% — same code, different feel.

The boss is a pattern test

The boss exists to test whether the player has learned the systems. The heavy slam is dodgeable if you read the telegraph. The summoned grunts force you to manage adds while watching the boss. The enrage phase punishes slow play. This is classic action game boss design: each mechanic is tested individually in the encounter. Your tuning panel lets you dial in exactly how forgiving or demanding each phase is.

🔍Why three enemy types is enough for a prototype

Three archetypes — melee, ranged, boss — cover the fundamental design space. Every other enemy in BloodRayne (or any action game) is a variant of these three. A fast melee enemy is a grunt with higher pursuit speed and lower health. A shotgun enemy is a ranged soldier with a spread pattern. A mini-boss is a boss with fewer phases. Once you have the tuning infrastructure for these three, creating new variants is just adjusting slider values and maybe adding one new state. Start with three, prove the design, then expand.


Customize it

Add a shield grunt variant

Add a "shield" checkbox to the Grunt tab. When enabled, the grunt holds a
shield (small gray rectangle in front). Frontal attacks deal 0 damage and
produce a "clang" particle effect (gray sparks). The player must dodge behind
the grunt to deal damage. The grunt turns to face the player every 0.8 seconds
(not instantly -- the turn delay is the exploit window). Add a Shield Turn
Speed slider (0.3-2.0 seconds, default 0.8).

Add enemy group coordination

When 2+ grunts are alive, they should coordinate attacks. Only one grunt
attacks at a time -- the others circle at detection range edge, waiting
their turn. After one grunt's attack cooldown expires, the next grunt
in the queue attacks. This prevents "enemy pile" where all grunts overlap
on the player simultaneously. Add a "Coordinated" checkbox to the Grunt tab.

Add a boss phase 2 attack

Give the boss a second attack pattern: a charge. After every other heavy
slam, instead of approaching slowly, the boss dashes toward the player at
300px/s across the full arena width. The charge is telegraphed with a 1-second
wind-up where the boss crouches (scale to 0.8x height, 1.2x width) and
the ground shakes. The charge deals 25 damage and continues past the player
to the far wall. The boss is vulnerable for 1.5 seconds after hitting the
wall (stagger state). Add a Charge Damage slider and Charge Stagger Duration
slider to the Boss tab.

Try it yourself

  1. Paste the prompt and open the sandbox in your browser.
  2. Add one of each enemy type. Turn on “Show AI States” and watch the state labels change in real time as you interact with each enemy.
  3. Set grunt aggression to 100%. Notice the difference. Set it to 0%. Notice the difference. Find the value where the grunt feels dangerous but fair.
  4. Fight the ranged soldier without dodging. Now fight it using only dodge rolls to close distance. The ranged soldier should force you to use dodge — if you can just walk up and combo it, increase its retreat speed or reduce its attack cooldown.
  5. Fight the boss. Die on purpose. Pay attention to the telegraph timing — if you cannot reliably dodge the heavy slam, the telegraph duration is too short. If you can stand in front of the boss and ignore the telegraph, it is too long.
  6. Add 3 grunts and 2 ranged soldiers at once. This is a “crowd” test. If you feel overwhelmed in under 5 seconds, reduce aggression. If you feel unchallenged, add more enemies or increase their stats.

Write down the values that felt best. You will need them when the AI stitches everything together in the demo assembly.


💡Your enemies have brains now

Not big brains — but enough to force the player to think. The grunt pressures, the ranged soldier controls space, and the boss demands respect. These three archetypes, with the tuning infrastructure you just built, can produce dozens of enemy variants. BloodRayne’s enemy roster is closer than it looks. Next up: making every hit, slash, and explosion feel like it matters.