Phaser AE

First-person bosses

Pro packv3.0.0-0ArcadeNew

Boss fights for first-person shooters: a big enemy that changes how it fights as its health falls, with every attack announced before it lands.

This is a Pro pack. Upgrade to Phaser Pro to use it in your games.See Phaser Pro →

Released October 24, 2026

First-person bosses: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

fpsBosses

function fpsBosses(): Pack<{ fpsBosses: typeof kit; }>

Compose boss fights under game.fpsBosses.

Helpers

createBosses

function createBosses(defs: BossDef[], horde: Horde, world: EnemyWorld, seed = 1): Bosses

Boss fights for the bosses of defs among horde's enemies, on world (the map's enemyWorld()). Throws on a def it cannot fight.

Classes

Bosses

class Bosses

Boss fights for first-person shooters, on top of fps-enemies: an enemy of a boss kind is taken over (the horde keeps its health, pain, death and sounds) and fought in phases set by its health. Each phase has a way of moving (holding, chasing, strafing, keeping away) and a pattern of attacks with warning wind-ups: fanned volleys, rings of shots, aimed bursts, charges, ground slams, summons and teleports. A new phase can bring invulnerability, healing and reinforcements; phases can carry armour. Projectiles, summons and damage come back as events for the game to apply, as the horde's do, so it works on any map an EnemyWorld describes. Get one from createBosses.

  • constructor(defs: BossDef[], horde: Horde, world: EnemyWorld, seed = 1)
  • adopt(id: string): boolean — Take over an enemy if its kind is a boss: returns true when it now fights as one. Call it for every enemy placed.
  • list(): BossState[] — The bosses, for a health bar.
  • has(id: string): boolean — Whether an enemy is a boss.
  • scale(id: string, damage: number): number — The damage a boss actually takes from damage: none while invulnerable, less with its phase's armour. Other enemies take it all.
  • tick(dt: number, player: BossTarget): BossEvent[] — Run the bosses on by dt seconds (0 to 1) against the player.
  • summoned(boss: string, enemy: string): void — Tell the bosses an enemy they summoned now stands (the game spawned it), so max counts it.
  • get state(): BossesState — A copy of the state.
  • restore(state: BossesState): void — Put back a saved state.

Types

BossAttack

type BossAttack = | { kind: 'volley'; count: number; spread: number; projectile: BossProjectile; damage: [number, number]; repeat?: number; interval?: number; windup?: number; sound?: string } | { kind: 'ring'; count: number; projectile: BossProjectile; damage: [number, number]; repeat?: number; interval?: number; windup?: number; sound?: string } | { kind: 'burst'; shots: number; interval: number; projectile: BossProjectile; damage: [number, number]; spread?: number; windup?: number; sound?: string } | { kind: 'charge'; speed: number; time: number; damage: [number, number]; windup?: number; sound?: string } | { kind: 'slam'; radius: number; damage: [number, number]; knock?: number; windup?: number; sound?: string } | { kind: 'summon'; enemy: string; count: number; radius?: number; max?: number; windup?: number; sound?: string } | { kind: 'teleport'; to?: 'near' | 'behind' | [number, number][]; windup?: number; sound?: string }

One attack in a boss's pattern. Every attack has a windup (seconds of warning, default 0.6) and may name a sound.

  • volley: count shots fanned across spread radians at the player, repeat times interval apart.
  • ring: count shots all round, repeat times interval apart (each ring turned half a gap).
  • burst: shots aimed shots interval apart, scattered by spread.
  • charge: a rush at the player at speed for up to time seconds, hurting on contact.
  • slam: a blow to the ground hurting a player within radius who is on the ground, and knocking them back.
  • summon: count enemies of kind enemy around it within radius, while fewer than max it summoned stand.
  • teleport: to a random point near the player, behind the player, or one of to's points.

BossDef

interface BossDef

A boss: an enemy kind that a horde already knows (its hit points, size and sprite), and how it fights.

  • id: string — The enemy kind it drives. Every enemy of this kind on the map becomes this boss.
  • name?: string — Its name, for the health bar; default the id.
  • phases: BossPhase[] — Its phases, first to last.
  • wake?: number — How near the player must come, in sight, to wake it; default 30. It wakes when hurt too.
  • sounds?: { wake?: string } — Sounds: as it wakes.

BossesState

interface BossesState

Everything that changes; a save holds exactly this.

  • bosses: Fight[] — Each boss's fight.
  • rng: number[] — The random stream.

BossEvent

type BossEvent = | { type: 'boss-wake'; id: string; name: string } | { type: 'boss-phase'; id: string; phase: number } | { type: 'boss-windup'; id: string; attack: string; time: number } | { type: 'projectile'; id: string; x: number; y: number; z: number; yaw: number; pitch: number; speed: number; radius: number; damage: number; splash?: { radius: number; damage: [number, number]; knock?: number } } | { type: 'slam'; id: string; x: number; z: number; radius: number; damage: number; knock: number } | { type: 'charge-hit'; id: string; damage: number } | { type: 'summon'; id: string; enemy: string; x: number; z: number; yaw: number } | { type: 'teleport'; id: string; x: number; z: number } | { type: 'boss-died'; id: string } | { type: 'sound'; id: string; sound: string; x: number; y: number; z: number }

What the bosses did. Projectiles, summons and damage are the game's to apply.

BossPhase

interface BossPhase

A stretch of a fight: how the boss moves and what it does until its health falls to until.

  • until?: number — The share of its health (0 to 1) at which the next phase begins; the last phase has none.
  • move?: 'hold' | 'chase' | 'strafe' | 'keep-away' — How it moves between attacks: 'hold' its ground, 'chase' the player, 'strafe' round them, or 'keep-away' at range. Default 'chase'.
  • speed?: number — Movement speed, units per second; default 2.5.
  • range?: number — Distance it keeps when strafing or keeping away; default 8.
  • attacks: BossAttack[] — Its attacks.
  • order?: 'cycle' | 'random' — 'cycle' through the attacks in order (default) or pick at 'random'.
  • pause?: [number, number] — Seconds between attacks, [min, max]; default [1, 2].
  • armor?: number — Damage it takes is multiplied by this, 0 (none) to 1 (all); default 1.
  • enter?: { sound?: string; invulnerable?: number; summon?: { enemy: string; count: number; radius?: number }; heal?: number } — What happens as the phase begins: a sound, seconds invulnerable, a summon, a share of health healed.

BossProjectile

interface BossProjectile

A boss's shot: speed and radius in world units, and an optional blast.

  • speed: number — Units per second.
  • radius: number — Radius.
  • splash?: { radius: number; damage: [number, number]; knock?: number } — A blast where it lands.

BossState

interface BossState

A boss now.

  • id: string — The enemy's id.
  • def: string — Its kind.
  • name: string — Its name.
  • hp: number — Hit points left.
  • max: number — Hit points at full health.
  • phase: number — Phase index.
  • awake: boolean — Awake and fighting.
  • dead: boolean — Dead.
  • stage: 'idle' | 'windup' | 'attack' — 'idle', 'windup' or 'attack'.
  • attack: string — The attack under way, by kind, or ''.
  • invulnerable: number — Seconds of invulnerability left.

BossTarget

interface BossTarget

The player as a boss sees them.

  • x: number — Position.
  • z: number — Position.
  • y?: number — Feet height; default 0.
  • height?: number — Height; default 1.6.
  • yaw?: number — Facing (for teleporting behind them); default 0.
  • grounded?: boolean — Standing on the ground (a slam only hurts the grounded); default true.
  • alive: boolean — Alive.