Skip to main content

Cameras

Cameras are attached to scenes and can be changed by setting Scene.camera. By default, a Scene is initialized with a Camera that doesn't move and is centered on the screen.

Focus

Cameras have a position (x, y) which means they center around a specific point.

If a camera is following an Actor, it will ensure the actor is always at the center of the screen. You can use Camera.x and Camera.y instead if you wish to offset the focal point.

Camera zooming

To adjust the zoom for your game, use Camera.zoom which will scale the game accordingly. You can pass a duration to transition between zoom levels.

This can be useful as a way to scale up your game.

Camera strategies

Cameras can implement a number of strategies to track, follow, or exhibit custom behavior in relation to a target. A common reason to use a strategy is to have the Camera follow an Actor.

In order to use the different built-in strategies, you can access Camera.strategy.

warning

It is important to add the camera strategy in your Engine, Scene, or Actor's onInitialize(), the strategy will automatically update itself so do not put it in a update/draw lifecycle event.

Lock the camera exactly to the center of the actor's bounding box

typescript
game.currentScene.camera.strategy.lockToActor(actor);
typescript
game.currentScene.camera.strategy.lockToActor(actor);

Lock the camera to one axis of the actor, in this case follow the actors x position

typescript
game.currentScene.camera.strategy.lockToActorAxis(actor, ex.Axis.X);
typescript
game.currentScene.camera.strategy.lockToActorAxis(actor, ex.Axis.X);

Elastically move the camera to an actor in a smooth motion see ElasticToActorStrategy for details

typescript
game.currentScene.camera.strategy.elasticToActor(actor, cameraElasticity, cameraFriction);
typescript
game.currentScene.camera.strategy.elasticToActor(actor, cameraElasticity, cameraFriction);

Keep the actor within a circle around the focus

typescript
game.currentScene.camera.strategy.radiusAroundActor(actor, radius);
typescript
game.currentScene.camera.strategy.radiusAroundActor(actor, radius);

Keep the camera limited within the given constraints.
Make sure that the camera bounds are at least as large as the viewport size.

typescript
let boundingBox = new BoundingBox(leftBorder, topBorder, rightBorder, bottomBorder);
game.currentScene.camera.strategy.limitCameraBounds(boundingBox);
typescript
let boundingBox = new BoundingBox(leftBorder, topBorder, rightBorder, bottomBorder);
game.currentScene.camera.strategy.limitCameraBounds(boundingBox);

Multiple strategies

Multiple strategies can be applied to the camera. Strategies are applied in the order they were added.

For example: Let's say a lockToActor strategy and a limitCameraBounds strategy is added, in that order. When the strategies are processed, the camera will first lock to the actor, then, as the camera approaches the configured bounds of limitCameraBounds it is limited to those contraints.

In this example, the limitCameraBounds applies its effect on top of the earlier lockToActor strategy.

Custom strategies

Custom strategies can be implemented by extending the CameraStrategy interface and added to cameras to build novel behavior with ex.Camera.addStrategy<T>(new MyCameraStrategy<T>()).

As shown below a camera strategy calculates a new camera position vector every frame given a target type, camera, engine, and elapsed delta in milliseconds.

typescript
/**
* Interface that describes a custom camera strategy for tracking targets
*/
export interface CameraStrategy<T> {
/**
* Target of the camera strategy that will be passed to the action
*/
target: T;
/**
* Camera strategies perform an action to calculate a new focus returned out of the strategy
*/
action: (target: T, camera: Camera, engine: Engine, elapsed: number) => Vector;
}
typescript
/**
* Interface that describes a custom camera strategy for tracking targets
*/
export interface CameraStrategy<T> {
/**
* Target of the camera strategy that will be passed to the action
*/
target: T;
/**
* Camera strategies perform an action to calculate a new focus returned out of the strategy
*/
action: (target: T, camera: Camera, engine: Engine, elapsed: number) => Vector;
}

When implementing custom strategies consider referencing the camera's current position with camera.getFocus() and calculate the next position from that vector. This allows strategies to be composed gracefully.

LockCameraToActorAxisStrategy sample:

typescript
export class LockCameraToActorAxisStrategy implements CameraStrategy<Actor> {
constructor(
public target: Actor,
public axis: Axis
) {}
public action = (target: Actor, cam: Camera, _eng: Engine, elapsed: number) => {
const center = target.center;
const currentFocus = cam.getFocus();
if (this.axis === Axis.X) {
return new Vector(center.x, currentFocus.y);
} else {
return new Vector(currentFocus.x, center.y);
}
};
}
typescript
export class LockCameraToActorAxisStrategy implements CameraStrategy<Actor> {
constructor(
public target: Actor,
public axis: Axis
) {}
public action = (target: Actor, cam: Camera, _eng: Engine, elapsed: number) => {
const center = target.center;
const currentFocus = cam.getFocus();
if (this.axis === Axis.X) {
return new Vector(center.x, currentFocus.y);
} else {
return new Vector(currentFocus.x, center.y);
}
};
}

When configuring your custom strategy the first argument, target, can be of any type. While Actor is commonly the target, it can anything, such as a BoundingBox.

Adding and removing strategies

In the above examples we used convenience helpers, such as game.currentScene.camera.strategy.lockToActor(actor), to add strategies to our scene. Occassionally you may need a bit more control over the strategy array. This can be done via the following methods and properties:

  • addStrategy<T extends CameraStrategy<any>[]>(...cameraStrategies: T)
    • Adds the given strategy to the end of the strategy array. The built in convenience helpers are wrappers for addStrategy().
    • Multiple strategies can be passed as arguments and they will be appended to the end of the strategy array.
  • removeStrategy<T>(cameraStrategy: CameraStrategy<T>)
    • Removes the given strategy from the strategy array.
  • clearAllStrategies()
    • Clears all camera strategies from the camera.
  • setStrategies<T extends CameraStrategy<any>[]>(cameraStrategies: T)
    • Overwrites the current array of strategies with the provided set.
  • strategies
    • The camera's strategy array

Camera shake

To add some fun effects to your game, the Camera.shake method will do a random shake. This is great for explosions, damage, and other in-game effects.

Camera lerp

"Lerp" is short for Linear Interpolation and it enables the camera focus to move smoothly between two points using timing functions. Use Camera.move to ease to a specific point using a provided EasingFunction.

typescript
export interface EasingFunction {
(currentTime: number, startValue: number, endValue: number, duration: number): number;
}
// or any builtin
const linear = ex.EasingFunctions.Linear;
const easinQuad = ex.EasingFunctions.EaseInQuad;
// ... and more!
typescript
export interface EasingFunction {
(currentTime: number, startValue: number, endValue: number, duration: number): number;
}
// or any builtin
const linear = ex.EasingFunctions.Linear;
const easinQuad = ex.EasingFunctions.EaseInQuad;
// ... and more!