arcade2d
Class

Camera

world/camera.ts:119

The world's viewport — a "look-at point" in world space, plus an orientation and a zoom factor — that downstream presentation components (notably Scene) use to decide what part of the world ends up on screen.

Every World owns exactly one Camera, attached automatically at construction and accessible as a typed reference via World.camera. There is no opt-in registration, no name to remember, and no risk of the camera being missing — engine code that reads it can treat its presence as an invariant.

Semantics

The camera is a look-at point, not a pan offset:

  • Camera.position is the world-space coordinate the camera is currently pointed at. Scene maps that point to the centre of the canvas — set camera.position to the player's position once per frame and the player stays anchored on screen as they move.
  • Camera.rotation is the camera's roll, in radians. Scene applies its inverse to the scene container, so increasing the value rotates the world clockwise underneath a stationary viewer.
  • Camera.zoom scales the rendered view; values greater than 1 zoom in (objects appear larger), values between 0 and 1 zoom out.

All three fields default to a neutral state. With the default camera, the world's origin appears at the centre of the canvas, the world's axes line up with the canvas's, and one world unit equals one screen pixel.

Shake

Camera.shake kicks off a temporary, decaying random offset applied to the rendered view — the staple "impact" feedback for hits, explosions, and screen-jolts. The shake lives entirely on the render side: it adjusts Camera.shakeOffset each tick during the camera's own onUpdate, and Scene reads that offset when it applies the container transform. The logical Camera.position and Camera.rotation are untouched, which means

  • Mouse (and any other code routing through Scene.screenToWorld) keeps landing on the world point the player actually aimed at, not a phantom shifted by the shake.
  • Game logic that reads camera.position (e.g. a follow controller centring on the player) sees a stable value, not a jittering one.

Intensity is expressed in screen pixels so the visual magnitude is independent of zoom. Starting a new shake while one is already in flight replaces it — the engine does not currently stack shakes.

Why this isn't a WorldObject

The camera looks superficially like it wants to be a WorldObject — it has a transform, it sometimes follows a moving target. But a WorldObject is a thing inside the world (findable by tag, iterated during update, destroyable). The camera is the lens through which the world is observed; modelling it as a sibling of every game entity conflates the two roles. As a world-scoped component it stays out of findByTag, never appears in object iteration, and can't be accidentally destroyed.

Example

// Camera-follow-player: copy the player's position into the camera once
// per frame so the player stays centred on screen. Run inside the
// player's `onUpdate` so Scene's post-update transform sync sees a
// settled camera before drawing.
class CameraFollow extends AbstractWorldObjectComponent {
  public onUpdate(): void {
    this.world.camera.position.copyFrom(this.host.position);
  }
}
// Shake the camera on every bullet impact.
onBulletHit() {
  world.camera.shake(8, 250);
}
// Zoom in for a cinematic close-up.
world.camera.zoom = 2;

Constructors

#
constructor(host: World): Camera

Parameters

Properties

#
enabled: boolean

Per-component gate on the three update hooks (onPreUpdate, onUpdate, onPostUpdate). When explicitly false, the engine skips all three for this component during the host's tick — useful for temporarily pausing behaviour (e.g. a freeze powerup) without removing the component and losing its internal state.

Does not gate onAdded or onDestroy; those always fire so a host can never end up with a half-attached component.

readonly #
host: World

The host this component is attached to. Stored read-only; subclasses access it as this.host directly, or through the tier-appropriate aliases (this.world, this.game) on the per-tier abstract bases.

readonly #
position: Point

The point in world space the camera is currently looking at. Mutable in place — game code typically writes to this every frame to follow a target (camera.position.copyFrom(player.position)).

Scene maps this point to the centre of the canvas every frame. With the default (0, 0), the world's origin appears centred on screen.

#
rotation: number

The camera's roll, in radians, measured clockwise (same convention as WorldObject.rotation and the rest of the engine). Mutable.

Scene applies the inverse of this rotation to the scene container, so increasing the value rotates the world clockwise beneath a stationary viewer.

#
zoom: number

Uniform zoom factor applied by Scene when projecting world coordinates to the screen. 1 (the default) is "1 world unit per 1 screen pixel"; values greater than 1 zoom in, values between 0 and 1 zoom out. Negative or zero values produce undefined visual results — neither the engine nor Pixi clamp them — so don't.

Accessors

readonly #
game: Game

The Game the host world belongs to. Always non-null — the world's game field is a mandatory construction argument, not an option.

readonly #
isShaking: boolean

true if a Camera.shake is currently in flight. Goes back to false automatically when the shake's duration elapses, or immediately on Camera.stopShake.

readonly #
shakeOffset: Readonly<Point>

The current shake-induced offset, in screen pixels. Zero unless a shake is in flight. Exposed primarily so Scene can read it during the post-update transform sync; game code rarely needs to inspect it directly.

The returned Point is the camera's live internal instance — mutating it externally is a contract violation. Treat it as read-only.

readonly #
world: World

The World this component is attached to — identical to AbstractComponent.host at this tier, exposed under the world name so subclass code reads the same on every tier.

Methods

#
onAdded(_deps: Record): void

Lifecycle hook that is called when the component is added to the host object. Should not be called directly.

Parameters

  • _deps Record

Returns

void
#
onDestroy(_deps: Record): void

Lifecycle hook that is called when the host object is destroyed. Should not be called directly.

Parameters

  • _deps Record

Returns

void
#
onUpdate(update: WorldUpdate): void

Advances any in-flight shake by one tick. Computes a fresh random offset inside a disc whose radius is the current (decayed) shake intensity, then writes that to Camera.shakeOffset for Scene to consume during the post-update phase.

Parameters

Returns

void
#
shake(intensity: number, duration: number): void

Starts a screen-shake effect. The shake adds a randomised offset to Camera.shakeOffset once per tick, decaying linearly from intensity at the start to zero at duration. Scene applies the offset on top of the camera's logical position when it draws.

Calling shake while another shake is still running replaces the previous one — the engine does not currently stack shakes. Passing a non-positive intensity or duration is a no-op (treated as a Camera.stopShake).

Parameters

  • intensity number
  • duration number

Returns

void
#
stopShake(): void

Cancels any in-flight shake and snaps Camera.shakeOffset back to zero on the next frame. Safe to call when no shake is active — it's a no-op in that case.

Returns

void
ESC