UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers from the team at Phaser Studio Inc.

498 lines (350 loc) 15.9 kB
--- name: cameras description: "Use this skill when working with cameras in Phaser 4. Covers camera effects (shake, fade, flash, pan, zoom), following sprites, scroll, bounds, viewports, multiple cameras, and minimap. Triggers on: camera, viewport, scroll, zoom, follow, shake, fade." --- # Cameras > Camera system in Phaser 4 -- CameraManager, main camera, viewport vs scroll, zoom, bounds, following sprites, camera effects (fade, flash, shake, pan, zoomTo, rotateTo), ignore lists, filters, and keyboard controls. **Key source paths:** `src/cameras/2d/CameraManager.js`, `src/cameras/2d/BaseCamera.js`, `src/cameras/2d/Camera.js`, `src/cameras/2d/effects/`, `src/cameras/controls/` **Related skills:** ../game-setup-and-config/SKILL.md, ../sprites-and-images/SKILL.md, ../filters-and-postfx/SKILL.md ## Quick Start ```js // In a Scene's create() method: // Access the default camera (created automatically) const cam = this.cameras.main; // Scroll the camera to look at a different part of the world cam.setScroll(200, 100); // Center camera on a world coordinate cam.centerOn(400, 300); // Zoom in (2x) -- values < 1 zoom out, > 1 zoom in cam.setZoom(2); // Follow a sprite with smooth lerp cam.startFollow(player, false, 0.1, 0.1); // Constrain the camera to the world bounds cam.setBounds(0, 0, 2048, 2048); // Fade in from black over 1 second cam.fadeIn(1000); // Add a filter to the camera (v4 feature) cam.filters.external.addBlur(1, 2); ``` ## Core Concepts ### CameraManager Every Scene has a `CameraManager` accessible via `this.cameras`. It manages all cameras for that Scene and is registered as a plugin under the key `'CameraManager'`. ```js // The manager is at this.cameras (not this.camera) this.cameras // CameraManager instance this.cameras.cameras // Array of Camera objects (render order) this.cameras.main // Reference to the "main" camera (first one by default) this.cameras.default // Un-transformed utility camera (not in the cameras array) ``` **Key methods on CameraManager:** | Method | Signature | Description | |---|---|---| | `add` | `(x?, y?, width?, height?, makeMain?, name?)` | Create a new Camera. Defaults to full game size at 0,0. Returns `Camera`. | | `addExisting` | `(camera, makeMain?)` | Add a pre-built Camera instance. Returns the Camera or `null` if it already exists. | | `remove` | `(camera, runDestroy?)` | Remove and optionally destroy a Camera or array of Cameras. If main is removed, resets to cameras[0]. | | `getCamera` | `(name)` | Find a Camera by its `name` string. Returns Camera or `null`. | | `getTotal` | `(isVisible?)` | Count cameras. Pass `true` to count only visible ones. | | `fromJSON` | `(config)` | Create cameras from a config object or array. Used for scene-level camera config. | | `resetAll` | `()` | Destroy all cameras and create one fresh default camera. | | `resize` | `(width, height)` | Resize all cameras to given dimensions. | **Camera limit:** The manager supports up to 32 cameras that can use `ignore()` for Game Object exclusion (IDs are bitmasks). Cameras beyond 32 get ID 0 and cannot exclude objects. ### Main Camera The `main` property is a convenience reference to a Camera, typically `cameras[0]`. It is set automatically when: - The scene boots (first camera created becomes main) - You pass `makeMain: true` to `add()` or `addExisting()` - The current main camera is removed (falls back to `cameras[0]`) ### Viewport vs World (Scroll) A Camera has two independent coordinate concepts: 1. **Viewport** -- The physical rectangle on the canvas where the Camera renders. Controlled by `setPosition(x, y)`, `setSize(w, h)`, or `setViewport(x, y, w, h)`. By default, fills the entire game canvas. 2. **Scroll** -- Where the Camera is "looking" in the game world. Controlled by `scrollX` / `scrollY` properties or `setScroll(x, y)`. Scrolling does not affect the viewport rectangle. ```js // Viewport: a 320x200 mini-map in the top-right corner const miniCam = this.cameras.add(480, 0, 320, 200); // Scroll: make the mini-map look at a different world area miniCam.setScroll(1000, 500); // Zoom: the mini-cam shows more of the world miniCam.setZoom(0.25); ``` **worldView** is a read-only `Rectangle` updated each frame that reflects what area of the world the camera can currently see, accounting for scroll, zoom, and bounds. Use it for culling or intersection checks. ```js const view = cam.worldView; // { x, y, width, height } ``` ## Common Patterns ### Scrolling the Camera ```js // Direct property access cam.scrollX = 100; cam.scrollY = 200; // Chainable setter cam.setScroll(100, 200); // Center the camera on a world coordinate cam.centerOn(500, 400); // Get the scroll values needed to center on a point (without moving) const point = cam.getScroll(500, 400); // returns Vector2 ``` ### Following a Sprite ```js // Instant follow (lerp = 1, the default) cam.startFollow(player); // Smooth follow with lerp (0..1, lower = smoother) cam.startFollow(player, false, 0.1, 0.1); // Full signature: // startFollow(target, roundPixels?, lerpX?, lerpY?, offsetX?, offsetY?) cam.startFollow(player, true, 0.05, 0.05, 0, -50); // Change lerp or offset after starting follow cam.setLerp(0.08, 0.08); cam.setFollowOffset(0, -50); // Dead zone: camera only scrolls when target leaves this rectangle cam.setDeadzone(200, 150); // Stop following cam.stopFollow(); ``` `startFollow` accepts any object with `x` and `y` properties -- it does not have to be a Game Object. Lerp of `1` snaps instantly; `0.1` gives smooth tracking. A lerp of `0` on an axis disables tracking on that axis. When a deadzone is set, the camera does not scroll while the target remains inside the deadzone rectangle. The deadzone is re-centered on the camera midpoint each frame. ### Zoom ```js // Uniform zoom cam.setZoom(2); // 2x zoom in cam.setZoom(0.5); // zoom out (see twice as much) // Independent horizontal/vertical zoom cam.setZoom(2, 1); // stretch horizontally // Read current zoom cam.zoom; // shortcut -- reads zoomX (assumes uniform) cam.zoomX; cam.zoomY; ``` **Never set zoom to 0.** The minimum is clamped to 0.001. ### Bounds ```js // Constrain scrolling to a world area cam.setBounds(0, 0, worldWidth, worldHeight); // Center on the new bounds immediately cam.setBounds(0, 0, 2048, 2048, true); // Temporarily disable bounds without removing them cam.useBounds = false; // Remove bounds entirely cam.removeBounds(); // Read the current bounds const rect = cam.getBounds(); // returns a new Rectangle copy ``` Bounds only restrict scrolling. They do not prevent Game Objects from being placed outside the bounds, and they do not affect the viewport position. ### Multiple Cameras ```js // Full-screen main camera const main = this.cameras.main; // Mini-map in top-right corner const minimap = this.cameras.add(600, 0, 200, 150).setZoom(0.2).setName('minimap'); minimap.setScroll(0, 0); minimap.setBackgroundColor('rgba(0,0,0,0.5)'); // HUD camera that doesn't scroll (ignores world objects, shows HUD layer only) const hudCam = this.cameras.add(0, 0, 800, 600).setName('hud'); hudCam.setScroll(0, 0); // Make the main camera ignore HUD objects main.ignore(hudGroup); // Make the HUD camera ignore world objects hudCam.ignore(worldGroup); // Find a camera by name const found = this.cameras.getCamera('minimap'); // Remove a camera this.cameras.remove(minimap); ``` ### Camera Effects All effects are on the `Camera` class (not `BaseCamera`). Each returns `this` for chaining. Effects that are already running will not restart unless you pass `force: true`. #### Fade ```js // Fade out to black over 1 second cam.fadeOut(1000); // Fade out to red cam.fadeOut(1000, 255, 0, 0); // Fade in from black over 500ms cam.fadeIn(500); // Lower-level: fade (out direction) and fadeFrom (in direction) // with a force parameter cam.fade(1000, 0, 0, 0, true); // force start even if running cam.fadeFrom(1000, 0, 0, 0, true); // With per-frame callback cam.fadeOut(1000, 0, 0, 0, (cam, progress) => { // progress goes from 0 to 1 }); ``` Fade direction: `fadeOut` / `fade` goes transparent-to-color. `fadeIn` / `fadeFrom` goes color-to-transparent. #### Flash ```js // White flash over 250ms (default) cam.flash(250); // Red flash over 500ms cam.flash(500, 255, 0, 0); // Full signature: flash(duration?, r?, g?, b?, force?, callback?, context?) cam.flash(300, 255, 255, 255, true, (cam, progress) => {}); ``` #### Shake ```js // Default shake: 100ms at intensity 0.05 cam.shake(100); // Stronger shake for 500ms cam.shake(500, 0.02); // Independent x/y intensity using a Vector2 cam.shake(300, new Phaser.Math.Vector2(0.1, 0.02)); // Full signature: shake(duration?, intensity?, force?, callback?, context?) ``` The `intensity` value is a small float. The default 0.05 means the camera shifts up to 5% of the viewport size. #### Pan ```js // Pan camera center to world coordinate (400, 300) over 2 seconds cam.pan(400, 300, 2000); // With easing cam.pan(400, 300, 2000, 'Power2'); // Full signature: pan(x, y, duration?, ease?, force?, callback?, context?) cam.pan(800, 600, 1500, 'Sine.easeInOut', false, (cam, progress, x, y) => {}); ``` Pan scrolls the camera so its viewport center finishes at the given world coordinate. #### ZoomTo ```js // Animate zoom to 2x over 1 second cam.zoomTo(2, 1000); // With easing cam.zoomTo(0.5, 2000, 'Cubic.easeOut'); // Full signature: zoomTo(zoom, duration?, ease?, force?, callback?, context?) ``` #### RotateTo ```js // Rotate camera to 45 degrees (in radians) over 1 second cam.rotateTo(Phaser.Math.DegToRad(45), false, 1000); // Shortest path rotation cam.rotateTo(Math.PI, true, 1500, 'Quad.easeInOut'); // Full signature: rotateTo(angle, shortestPath?, duration?, ease?, force?, callback?, context?) ``` The angle is in **radians**. Set `shortestPath` to `true` to take the shortest rotation direction. #### Reset All Effects ```js cam.resetFX(); // stops and resets all running effects (rotate, pan, shake, flash, fade) ``` ### Keyboard Controls Phaser provides two built-in camera control classes. Both require you to call `update(delta)` in your scene's `update` method. #### FixedKeyControl Moves at a fixed speed per frame. No smoothing. ```js // In create(): const cursors = this.input.keyboard.createCursorKeys(); this.camControl = new Phaser.Cameras.Controls.FixedKeyControl({ camera: this.cameras.main, left: cursors.left, right: cursors.right, up: cursors.up, down: cursors.down, speed: 0.5 // can also be { x: 0.5, y: 0.3 } }); // In update(time, delta): this.camControl.update(delta); ``` #### SmoothedKeyControl Applies acceleration, drag, and max speed for smooth camera movement. ```js this.camControl = new Phaser.Cameras.Controls.SmoothedKeyControl({ camera: this.cameras.main, left: cursors.left, right: cursors.right, up: cursors.up, down: cursors.down, zoomIn: this.input.keyboard.addKey('Q'), zoomOut: this.input.keyboard.addKey('E'), zoomSpeed: 0.02, acceleration: 0.06, drag: 0.0005, maxSpeed: 1.0 }); // In update(time, delta): this.camControl.update(delta); ``` Both controls support `zoomIn` and `zoomOut` keys and a `zoomSpeed` config value. ### Ignore Lists The `ignore` method updates a Game Object's `cameraFilter` bitmask so the camera skips rendering it. ```js // Ignore a single object cam.ignore(uiText); // Ignore an array cam.ignore([scoreText, livesIcon, pauseButton]); // Ignore all children in a Group cam.ignore(uiGroup); // Ignore a Layer and all its children cam.ignore(uiLayer); ``` This is the primary mechanism for HUD-style setups: one camera ignores world objects, another ignores HUD objects. ### Camera Deadzone The deadzone defines a rectangular area around the follow target where the camera does not scroll. The camera only moves when the target leaves this rectangle. ```js // Set a deadzone of 200x150 pixels centered on the camera viewport cam.setDeadzone(200, 150); // Access the deadzone rectangle (read-only, updated internally) console.log(cam.deadzone); // Phaser.Geom.Rectangle or null // Remove the deadzone cam.setDeadzone(); ``` ### World Point Conversion Convert screen (pointer) coordinates to world coordinates, accounting for scroll, zoom, and rotation: ```js const worldPoint = cam.getWorldPoint(pointer.x, pointer.y); // Reuse an output object to avoid allocation const output = new Phaser.Math.Vector2(); cam.getWorldPoint(pointer.x, pointer.y, output); ``` Essential when working with scrolled/zoomed cameras -- raw pointer coordinates are screen space, not world space. ### Camera Render List Each frame, `renderList` is populated with Game Objects visible to this camera. Rebuilt every frame. ```js const visible = cam.renderList; // array of GameObjects rendered this frame ``` ### Force Composite (Offscreen Framebuffer) Force the camera to render to an offscreen framebuffer. Required for `CaptureFrame` and similar features. ```js cam.setForceComposite(true); // enable offscreen framebuffer cam.setForceComposite(false); // disable ``` Filters enable framebuffer rendering automatically. Use `setForceComposite(true)` when you need it without filters. ### Filters on Cameras (v4) In Phaser 4, `Camera` has a `filters` property with two `FilterList` instances: ```js cam.filters.internal // FilterList -- applied by the system cam.filters.external // FilterList -- for user-added filters ``` Add post-processing effects to a camera the same way you add them to Game Objects: ```js // Add a blur filter to the camera cam.filters.external.addBlur(1, 2); // Add a glow cam.filters.external.addGlow(0xff0000, 4, 0, false, 0.1, 10); // Add a color matrix filter const fx = cam.filters.external.addColorMatrix(); fx.grayscale(); // Remove all external filters cam.filters.external.clear(); ``` Filters require WebGL. The camera must render via a framebuffer when filters are active. See `setForceComposite(true)` to explicitly enable this even without filters. ## Events Camera events are emitted on the Camera instance itself (it extends `EventEmitter`). Listen with `cam.on(event, handler)`. | Event constant | Dispatched when | |---|---| | `Phaser.Cameras.Scene2D.Events.FADE_IN_START` | `fadeIn` / `fadeFrom` begins | | `Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE` | Fade-in finishes | | `Phaser.Cameras.Scene2D.Events.FADE_OUT_START` | `fadeOut` / `fade` begins | | `Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE` | Fade-out finishes | | `Phaser.Cameras.Scene2D.Events.FLASH_START` | Flash begins | | `Phaser.Cameras.Scene2D.Events.FLASH_COMPLETE` | Flash finishes | | `Phaser.Cameras.Scene2D.Events.SHAKE_START` | Shake begins | | `Phaser.Cameras.Scene2D.Events.SHAKE_COMPLETE` | Shake finishes | | `Phaser.Cameras.Scene2D.Events.PAN_START` | Pan begins | | `Phaser.Cameras.Scene2D.Events.PAN_COMPLETE` | Pan finishes | | `Phaser.Cameras.Scene2D.Events.ZOOM_START` | Zoom effect begins | | `Phaser.Cameras.Scene2D.Events.ZOOM_COMPLETE` | Zoom effect finishes | | `Phaser.Cameras.Scene2D.Events.ROTATE_START` | RotateTo begins | | `Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETE` | RotateTo finishes | | `Phaser.Cameras.Scene2D.Events.FOLLOW_UPDATE` | Camera updates its follow position (each frame while following). Args: `(camera, target)` | | `Phaser.Cameras.Scene2D.Events.PRE_RENDER` | Before the camera renders | | `Phaser.Cameras.Scene2D.Events.POST_RENDER` | After the camera renders | | `Phaser.Cameras.Scene2D.Events.DESTROY` | Camera is destroyed | ```js cam.on(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => { this.scene.start('GameOver'); }); ``` For detailed configuration options, API reference tables, and source file maps, see [the reference guide](references/REFERENCE..//SKILL.md).