关于 cameras
面向 Phaser 4 游戏开发者的摄像机技能,介绍摄像机管理、移动、效果、多视图和控制方式。
主要功能
- 01管理场景中的摄像机
- 02设置视口、滚动、缩放和边界
- 03跟随目标并设置死区
- 04应用淡入淡出、闪烁、震动、平移和旋转效果
- 05配置多摄像机及忽略列表
- 06使用键盘控制摄像机
适用场景
- 01在主视图旁创建小地图
- 02平滑跟随玩家移动
- 03用不同摄像机分离 HUD 与游戏世界
- 04将指针坐标转换为世界坐标
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ phaserjs/ phaser --skill cameras安装后在 Claude Code 中输入/cameras确认已加载。
附带文件references/REFERENCE.md
详细介绍
摄像机
Phaser 4 中的摄像机系统 —— CameraManager、主摄像机、视口与滚动、缩放、边界、跟随精灵、摄像机效果(fade、flash、shake、pan、zoomTo、rotateTo)、忽略列表、滤镜以及键盘控制。
关键源码路径: src/cameras/2d/CameraManager.js、src/cameras/2d/BaseCamera.js、src/cameras/2d/Camera.js、src/cameras/2d/effects/、src/cameras/controls/
相关技能: ../game-setup-and-config/SKILL.md、../sprites-and-images/SKILL.md、../filters-and-postfx/SKILL.md
快速开始
// 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);
核心概念
CameraManager
每个 Scene 都有一个可通过 this.cameras 访问的 CameraManager。它管理该 Scene 的所有摄像机,并以 'CameraManager' 为键注册为插件。
// 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)
CameraManager 的关键方法:
| 方法 | 签名 | 描述 |
|---|---|---|
add | (x?, y?, width?, height?, makeMain?, name?) | 创建一个新摄像机。默认位于 0,0,尺寸为整个游戏尺寸。返回 Camera。 |
addExisting | (camera, makeMain?) | 添加一个预先构建好的摄像机实例。返回该摄像机,若已存在则返回 null。 |
remove | (camera, runDestroy?) | 移除并可选择销毁一个摄像机或摄像机数组。若主摄像机被移除,则重置为 cameras[0]。 |
getCamera | (name) | 通过 name 字符串查找摄像机。返回摄像机或 null。 |
getTotal | (isVisible?) | 统计摄像机数量。传入 true 则只统计可见的摄像机。 |
fromJSON | (config) | 从配置对象或数组创建摄像机。用于场景级别的摄像机配置。 |
resetAll | () | 销毁所有摄像机并创建一个全新的默认摄像机。 |
resize | (width, height) | 将所有摄像机调整为给定尺寸。 |
摄像机数量限制: 管理器最多支持 32 个可使用 ignore() 排除 Game Object 的摄像机(ID 为位掩码)。超过 32 个的摄像机 ID 为 0,无法排除对象。
主摄像机
main 属性是指向某个摄像机的便捷引用,通常是 cameras[0]。它会在以下情况自动设置:
- 场景启动时(第一个创建的摄像机成为主摄像机)
- 向
add()或addExisting()传入makeMain: true时 - 当前主摄像机被移除时(回退到
cameras[0])
视口与世界(滚动)
摄像机有两个相互独立的坐标概念:
-
视口 —— 摄像机在画布上渲染的物理矩形区域。通过
setPosition(x, y)、setSize(w, h)或setViewport(x, y, w, h)控制。默认情况下填满整个游戏画布。 -
滚动 —— 摄像机在游戏世界中“看向”的位置。通过
scrollX/scrollY属性或setScroll(x, y)控制。滚动不影响视口矩形。
// 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 是一个只读的 Rectangle,每帧更新,反映摄像机当前能看到的世界区域,已考虑滚动、缩放和边界。可用于剔除或相交检测。
const view = cam.worldView; // { x, y, width, height }
常见模式
滚动摄像机
// 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
跟随精灵
// 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 接受任何具有 x 和 y 属性的对象 —— 不必是 Game Object。lerp 为 1 时会立即吸附;0.1 可实现平滑跟踪。某一轴上的 lerp 为 0 会禁用该轴上的跟踪。
设置死区后,只要目标仍在死区矩形内,摄像机就不会滚动。每帧死区都会以摄像机中点重新居中。
缩放
// 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;
切勿将缩放设为 0。 最小值会被钳制为 0.001。
边界
// 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
边界仅限制滚动。它们不会阻止 Game Object 被放置在边界之外,也不影响视口位置。
多摄像机
// 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 类上(而非 BaseCamera)。每个方法都返回 this 以支持链式调用。已在运行的效果不会重新启动,除非传入 force: true。
淡入淡出
// 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
});
淡入淡出方向:fadeOut / fade 从透明到颜色。fadeIn / fadeFrom 从颜色到透明。
Flash
// 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
// 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?)
intensity 值是一个小浮点数。默认值 0.05 表示相机最多偏移视口尺寸的 5%。
Pan
// 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 会滚动相机,使其视口中心最终停在给定的世界坐标处。
ZoomTo
// 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
// 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?)
角度单位为弧度。将 shortestPath 设为 true 可沿最短旋转方向旋转。
重置所有效果
cam.resetFX(); // stops and resets all running effects (rotate, pan, shake, flash, fade)
键盘控制
Phaser 提供了两个内置的相机控制类。两者都需要你在场景的 update 方法中调用 update(delta)。
FixedKeyControl
每帧以固定速度移动。无平滑处理。
// 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
应用加速度、阻力和最大速度,实现平滑的相机移动。
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);
两种控制都支持 zoomIn 和 zoomOut 按键以及 zoomSpeed 配置值。
忽略列表
ignore 方法会更新游戏对象的 cameraFilter 位掩码,使相机跳过渲染该对象。
// 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);
这是 HUD 式设置的主要机制:一个相机忽略世界对象,另一个相机忽略 HUD 对象。
相机死区
死区定义了跟随目标周围的一个矩形区域,相机在此区域内不会滚动。只有当目标离开此矩形时,相机才会移动。
// 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();
世界点转换
将屏幕(指针)坐标转换为世界坐标,同时考虑滚动、缩放和旋转:
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);
在处理已滚动/缩放的相机时至关重要——原始指针坐标属于屏幕空间,而非世界空间。
相机渲染列表
每一帧,renderList 都会填入对该相机可见的游戏对象。每帧都会重建。
const visible = cam.renderList; // array of GameObjects rendered this frame
强制合成(离屏帧缓冲)
强制相机渲染到离屏帧缓冲。这是 CaptureFrame 及类似功能所必需的。
cam.setForceComposite(true); // enable offscreen framebuffer
cam.setForceComposite(false); // disable
滤镜会自动启用帧缓冲渲染。当你需要帧缓冲但不想使用滤镜时,请使用 setForceComposite(true)。
相机上的滤镜(v4)
在 Phaser 4 中,Camera 有一个 filters 属性,包含两个 FilterList 实例:
cam.filters.internal // FilterList -- applied by the system
cam.filters.external // FilterList -- for user-added filters
像为游戏对象添加后处理效果一样,为相机添加后处理效果:
// 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();
滤镜需要 WebGL。当滤镜处于活动状态时,相机必须通过帧缓冲进行渲染。即使没有滤镜,也可通过 setForceComposite(true) 显式启用此功能。
事件
摄像机事件在 Camera 实例自身上触发(它继承自 EventEmitter)。使用 cam.on(event, handler) 监听。
| 事件常量 | 触发时机 |
|---|---|
Phaser.Cameras.Scene2D.Events.FADE_IN_START | fadeIn / fadeFrom 开始 |
Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE | 淡入完成 |
Phaser.Cameras.Scene2D.Events.FADE_OUT_START | fadeOut / fade 开始 |
Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE | 淡出完成 |
Phaser.Cameras.Scene2D.Events.FLASH_START | 闪光开始 |
Phaser.Cameras.Scene2D.Events.FLASH_COMPLETE | 闪光完成 |
Phaser.Cameras.Scene2D.Events.SHAKE_START | 震动开始 |
Phaser.Cameras.Scene2D.Events.SHAKE_COMPLETE | 震动完成 |
Phaser.Cameras.Scene2D.Events.PAN_START | 平移开始 |
Phaser.Cameras.Scene2D.Events.PAN_COMPLETE | 平移完成 |
Phaser.Cameras.Scene2D.Events.ZOOM_START | 缩放效果开始 |
Phaser.Cameras.Scene2D.Events.ZOOM_COMPLETE | 缩放效果完成 |
Phaser.Cameras.Scene2D.Events.ROTATE_START | RotateTo 开始 |
Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETE | RotateTo 完成 |
Phaser.Cameras.Scene2D.Events.FOLLOW_UPDATE | 摄像机更新其跟随位置(跟随时每帧触发)。参数:(camera, target) |
Phaser.Cameras.Scene2D.Events.PRE_RENDER | 摄像机渲染之前 |
Phaser.Cameras.Scene2D.Events.POST_RENDER | 摄像机渲染之后 |
Phaser.Cameras.Scene2D.Events.DESTROY | 摄像机被销毁 |
cam.on(Phaser.Cameras.Scene2D.Events.FADE_OUT_COMPLETE, () => {
this.scene.start('GameOver');
});
有关详细的配置选项、API 参考表和源文件映射,请参阅参考指南。