mcpField
C
cameras

cameras

github.com/phaserjs开发40.6k900 次安装10 周前更新
代码仓库

关于 cameras

面向 Phaser 4 游戏开发者的摄像机技能,介绍摄像机管理、移动、效果、多视图和控制方式。

主要功能

  1. 01管理场景中的摄像机
  2. 02设置视口、滚动、缩放和边界
  3. 03跟随目标并设置死区
  4. 04应用淡入淡出、闪烁、震动、平移和旋转效果
  5. 05配置多摄像机及忽略列表
  6. 06使用键盘控制摄像机

适用场景

  1. 01在主视图旁创建小地图
  2. 02平滑跟随玩家移动
  3. 03用不同摄像机分离 HUD 与游戏世界
  4. 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])
视口与世界(滚动)

摄像机有两个相互独立的坐标概念:

  1. 视口 —— 摄像机在画布上渲染的物理矩形区域。通过 setPosition(x, y)、setSize(w, h) 或 setViewport(x, y, w, h) 控制。默认情况下填满整个游戏画布。

  2. 滚动 —— 摄像机在游戏世界中“看向”的位置。通过 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_STARTfadeIn / fadeFrom 开始
Phaser.Cameras.Scene2D.Events.FADE_IN_COMPLETE淡入完成
Phaser.Cameras.Scene2D.Events.FADE_OUT_STARTfadeOut / 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_STARTRotateTo 开始
Phaser.Cameras.Scene2D.Events.ROTATE_COMPLETERotateTo 完成
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 参考表和源文件映射,请参阅参考指南。

评论

支持 Markdown