Phaser AE

First-person weapons

Pro packv3.0.0-0ArcadeNew

The guns of a first-person shooter as rules. You trace the shots against your world; the arsenal decides when they fire, how many pellets, how hard they hit and what is left in the pouch.

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

Released October 24, 2026

First-person weapons: 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

fpsWeapons

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

Compose the weapons and ammunition rules under game.fpsWeapons.

Helpers

createArsenal

function createArsenal(config: ArsenalConfig): Arsenal

Make an arsenal. Throws, naming the field, on a config it cannot use.

scaleDamage

function scaleDamage(damage: number, dist: number, falloff?: { from: number; to: number; min: number }): number

Damage after falloff: full up to falloff.from cells, falling linearly to falloff.min of it at falloff.to cells and beyond. Without a falloff, the damage unchanged. Rounded to a whole number.

Classes

Arsenal

class Arsenal

A player's weapons and ammunition: which are carried, which is in hand, the trigger, rates of fire, raising and lowering, automatic switching when a weapon runs dry, and pickups. It decides when a shot goes off and with what pellets and damage; the game resolves each pellet against its world (cell-dungeon's ray, its enemies). Time moves only through tick. Get one from createArsenal.

  • constructor(config: ArsenalConfig)
  • get state(): ArsenalState — A copy of the state.
  • get current(): WeaponDef — The weapon in hand.
  • get owned(): string[] — The weapons carried, best last.
  • ammo(type: string): number — Ammunition carried of a type (0 for an unknown type).
  • get rounds(): number | null — Ammunition for the weapon in hand, or null when it needs none.
  • weapon(id: string): WeaponDef | undefined — A weapon's definition, or undefined.
  • get view(): { phase: ArsenalState['phase']; raised: number; recoil: number } — How far the weapon in hand is through raising (0 to 1, 1 when ready), for drawing it coming up or going down.
  • trigger(held: boolean): void — Hold or release the trigger.
  • select(id: string): boolean — Switch to a carried weapon: the one in hand lowers, then this one rises. False when it is not carried or already in hand.
  • cycle(direction: 1 | -1): boolean — Switch to the next (1) or previous (−1) carried weapon that can fire.
  • give(id: string, ammo = 0): ArsenalEvent[] — Pick up a weapon (with ammo rounds of its type, default 0): it is carried from now on. Switches to it when it is better than the one in hand.
  • addAmmo(type: string, amount: number): number — Add ammunition, up to the type's maximum. Returns how much was taken (0 when full or unknown).
  • max(type: string): number — The most of an ammunition type that can be carried now; 0 for an unknown type.
  • setMax(type: string, max: number): void — Carry more of an ammunition type (a backpack): the maximum becomes max, 1 to 100000. Unknown types are ignored.
  • tick(dt: number): { shots: WeaponShot[]; events: ArsenalEvent[] } — Run the arsenal on by dt seconds (0 to 10): raising and lowering, cooldowns, and shots while the trigger allows.
  • restore(state: ArsenalState): void — Put back a saved state. Throws on one that names weapons this arsenal lacks.

Types

AmmoDef

interface AmmoDef

An ammunition type.

  • id: string — Unique id.
  • max: number — Most that can be carried, 1 to 100000.
  • start?: number — How much a new arsenal has; default 0.

ArsenalConfig

interface ArsenalConfig

A player's arsenal.

  • weapons: WeaponDef[] — Every weapon there is, in order of preference (later is better when switching automatically). 1 to 32.
  • ammo: AmmoDef[] — Every ammunition type.
  • owned?: string[] — Weapons carried at the start; default the first.
  • current?: string — The weapon in hand at the start; default the best owned one with ammunition.
  • autoSwitch?: boolean — Switch to the best owned weapon with ammunition when the one in hand runs dry; default true.
  • seed?: number — Seed for damage and spread, 0 to 4294967295; default 1.

ArsenalEvent

type ArsenalEvent = | { type: 'switched'; weapon: string } | { type: 'empty'; weapon: string } | { type: 'picked-up'; weapon: string }

What a step did besides firing.

ArsenalState

interface ArsenalState

Everything that changes; a save holds exactly this.

  • owned: string[] — Weapons carried, by id, in the config's order.
  • ammo: Record<string, number> — Ammunition by type.
  • current: string — The weapon in hand (or being raised).
  • phase: 'ready' | 'cooldown' | 'lowering' | 'raising' — 'ready', 'cooldown' (between shots), 'lowering' or 'raising'.
  • timer: number — Seconds left in the phase.
  • next: string | null — The weapon to raise once this one is lowered, or null.
  • held: boolean — Whether the trigger is held.
  • spent: boolean — Whether this press has already fired (one-shot weapons).
  • shots: number — Shots fired.
  • rng: number[] — The random stream.
  • maxes?: Record<string, number> — Ammunition maximums raised above the config's (a backpack), by type.

WeaponDef

interface WeaponDef

A weapon.

  • id: string — Unique id, 1 to 100 characters.
  • kind: WeaponKind — 'hitscan' (an instant ray per pellet), 'projectile' (something that flies) or 'melee' (a short reach).
  • damage: [number, number] — Damage per pellet, [min, max] whole numbers from 0 to 10000, drawn evenly.
  • rate: number — Seconds between shots, 0.03 to 10.
  • auto?: boolean — True: fires again while the trigger is held. False (default): one shot per press.
  • ammo?: string — The ammunition type it uses; none (the default) for a weapon that needs none.
  • cost?: number — Ammunition per shot, 1 to 100; default 1.
  • pellets?: number — Pellets (rays or projectiles) per shot, 1 to 64; default 1.
  • spread?: number — Half-angle of the cone pellets scatter in, radians, 0 to 1; default 0.
  • range?: number — Reach in cells, 0.5 to 512; default 64, or 1.5 for melee.
  • falloff?: { from: number; to: number; min: number } — Damage falls from full at from cells to min (0 to 1) at to cells; default none.
  • projectile?: { speed: number; radius: number; splash?: { radius: number; damage: [number, number]; knock?: number } } — Projectile weapons: speed in units per second, radius in units, and splash damage around where it lands, with knock, how hard the blast pushes bodies away (units per second at its centre; default 0).
  • raise?: number — Seconds to raise it when switched to, 0 to 5; default 0.2.
  • lower?: number — Seconds to lower it when switching away, 0 to 5; default 0.2.
  • noise?: number — How many units away a shot is heard, 0 to 256; default 16, or 0 for melee.
  • sound?: string — The sound of a shot, by name, for the game to play; default none.

WeaponKind

type WeaponKind = 'hitscan' | 'projectile' | 'melee'

How a weapon delivers its damage.

WeaponShot

interface WeaponShot

One shot: what the game resolves against the world.

  • weapon: string — The weapon's id.
  • kind: WeaponKind — How it delivers damage.
  • pellets: { yaw: number; damage: number }[] — Each pellet: its angle off the aim (radians, positive turns right like the engine's yaw) and its damage before falloff.
  • range: number — Reach in cells.
  • noise: number — Units away it is heard.
  • sound?: string — The weapon's sound, if it has one.
  • falloff?: { from: number; to: number; min: number } — The falloff to apply by distance with scaleDamage, if any.
  • projectile?: { speed: number; radius: number; splash?: { radius: number; damage: [number, number]; knock?: number } } — Projectile settings, for projectile weapons.