Lesson 18
Boss fights: pressure, pattern, payoff.
A boss is not just a big enemy with more health. It is a test of what the player has learned, with attacks that are dangerous but readable.
1. Give the boss phases
Phases make a fight feel like it is escalating. The simplest version changes behavior at health thresholds. Above 70 percent, the boss teaches one attack. Below 40 percent, it combines attacks or shortens cooldowns. The player should feel the fight changing without being surprised by unfair damage.
function bossPhase(boss) {
const hpRatio = boss.hp / boss.maxHp;
if (hpRatio <= 0.35) return 3;
if (hpRatio <= 0.7) return 2;
return 1;
}
function updateBoss(boss, player, dt) {
boss.cooldown -= dt;
boss.phase = bossPhase(boss);
if (boss.cooldown > 0 || boss.telegraph) return;
const attack =
boss.phase === 1 ? "slam" :
boss.phase === 2 ? choose(["slam", "dash"]) :
choose(["slam", "dash", "ring"]);
startBossTelegraph(boss, attack);
}
Source pattern: Supagames action and tower defense games use boss enemy types, larger health pools, wave escalation and distinct rewards to mark major encounters.
The phase function should be easy to read. If the fight feels wrong, you can immediately see which phase is active and what attacks it allows.
2. Telegraph before damage
Fair boss damage is announced. A red circle appears before a slam. A line appears before a dash. The boss pauses, flashes or plays a warning sound. The player gets a small window to react. Without telegraphs, the fight becomes memorization or luck.
function startBossTelegraph(boss, attack) {
boss.telegraph = {
attack,
time: 0.65,
maxTime: 0.65,
x: boss.x,
y: boss.y
};
}
function updateTelegraph(boss, dt) {
if (!boss.telegraph) return;
boss.telegraph.time -= dt;
if (boss.telegraph.time <= 0) {
performBossAttack(boss, boss.telegraph.attack);
boss.telegraph = null;
boss.cooldown = boss.phase === 3 ? 0.8 : 1.25;
}
}
Telegraph time is a difficulty knob. Easy mode can use longer telegraphs. Hard mode can shorten them, but should not remove them completely.
3. Build attacks as small functions
Each attack should be a function that creates hitboxes, projectiles or arena hazards. Do not put every boss move inside one giant update function. Small attacks are easier to test and easier to combine into phases.
function performBossAttack(boss, attack) {
if (attack === "slam") {
hazards.push({ type: "circle", x: boss.x, y: boss.y, r: 70, life: 0.18, damage: 20 });
screenShake = 10;
}
if (attack === "dash") {
const angle = Math.atan2(player.y - boss.y, player.x - boss.x);
boss.vx = Math.cos(angle) * 520;
boss.vy = Math.sin(angle) * 520;
boss.dashTime = 0.28;
}
if (attack === "ring") {
for (let i = 0; i < 12; i++) {
spawnProjectile(boss.x, boss.y, i * Math.PI * 2 / 12);
}
}
}
This design also lets you reuse attacks. A mini-boss can use only `slam`, while the final boss combines all three.
4. Use arena pressure, not only damage
Boss fights are more interesting when the arena matters. Falling rocks can block safe routes. Summoned minions can force movement. A shrinking safe zone can create urgency. The danger is overloading the player. Add one pressure layer at a time and make it visible.
function spawnMinionWave(boss) {
const points = [
{ x: 80, y: 80 },
{ x: canvas.width - 80, y: 80 },
{ x: canvas.width / 2, y: canvas.height - 80 }
];
for (const p of points) {
enemies.push({
type: "minion",
x: p.x,
y: p.y,
hp: 20 + boss.phase * 8,
speed: 80 + boss.phase * 15
});
}
}
Minions should serve the boss design. If they simply distract from a boring boss, they become noise. If they force the player to use movement learned earlier, they become part of the exam.
5. Reward victory with state change
A boss should change the game after defeat. Open the exit, award an upgrade, unlock a chapter, change the music or show a short dialogue. If the reward is only score, the fight can feel detached from the world.
function defeatBoss(boss) {
boss.dead = true;
state.bossDefeated = true;
state.keys.crystal = true;
openDialogue("Gatekeeper", [
"The gate remembers your courage.",
"Take the crystal. The lower vault is awake."
], function () {
unlockDoor("vault");
saveGame();
});
}
For longer games, connect boss defeat to story state. The player should know why the fight mattered.
6. Boss QA checklist
- Can the player understand each attack before taking damage?
- Can the fight be won without perfect reflexes on normal difficulty?
- Does each phase add one idea instead of three?
- Does the boss stop attacking after defeat?
- Does victory unlock a clear next step?
- Does the fight work on mobile controls without covering danger zones?
A boss fight is a conversation with the player. It says: here are the rules, here is the pressure, now show what you learned.