用途
Scenes(场景)是 Phaser 游戏的组织骨架。每个场景拥有独立的生命周期(init、preload、create、update)、独立的注入系统(this.add、this.input、this.cameras 等),并且可以启动、停止、暂停、休眠,或与其他场景并行运行。ScenePlugin(this.scene)负责所有多场景编排。
关键源码路径:src/scene/Scene.js、src/scene/Systems.js、src/scene/SceneManager.js、src/scene/ScenePlugin.js、src/scene/Settings.js、src/scene/const.js、src/scene/events/、src/scene/InjectionMap.js。
主要能力
场景生命周期
生命周期由 SceneManager.bootScene() 和 SceneManager.create() 驱动,共 10 个状态:
- PENDING (0):场景已注册但尚未启动。
- INIT (1):若定义了 scene.init(data) 则调用,数据来自 settings.data。
- START (2):Systems.start() 触发,发出 start 和 ready 事件。
- LOADING (3):若定义了 scene.preload() 则调用,加载器运行,完成后进入 create。
- CREATING (4):若定义了 scene.create(data) 则调用,data 与 init 相同。
- RUNNING (5):每帧调用 scene.update(time, delta),场景渲染。
- PAUSED (6):不更新,但仍渲染。
- SLEEPING (7):不更新也不渲染,状态保留在内存中。
- SHUTDOWN (8):场景关闭,系统发出 shutdown,可重启。
- DESTROYED (9):场景完全销毁,无法重启。
状态常量位于 Phaser.Scenes,如 Phaser.Scenes.PENDING、Phaser.Scenes.RUNNING 等。
无 preload 时的流程:init() -> create() -> update() 循环(完全跳过 preload)。 有 preload 时的流程:init() -> preload() -> 加载器运行 -> create() -> update() 循环。
场景注入属性
这些属性通过 InjectionMap(src/scene/InjectionMap.js)注入到每个场景实例。
全局管理器(所有场景共享):this.game、this.renderer、this.anims、this.cache、this.plugins、this.registry、this.scale、this.sound、this.textures。
场景专属系统(每个场景唯一):this.sys、this.events、this.cameras、this.add、this.make、this.scene、this.children、this.lights、this.data、this.input、this.load、this.time、this.tweens、this.physics、this.matter。
可通过场景配置自定义注入映射,例如将 add 重命名为 makeStuff、load 重命名为 loader。
场景管理器
SceneManager(src/scene/SceneManager.js)是游戏级系统,不应直接调用其方法,而应使用 this.scene(ScenePlugin)。它维护有序的场景数组(决定渲染/更新顺序),在每个游戏步骤开始时处理操作队列(start、stop、sleep 等)。所有 ScenePlugin 方法都是排队执行,而非立即执行(下一帧执行)。
使用方式
场景切换
- start():关闭当前场景,启动目标场景。
- restart():关闭并重启同一场景。
- switch():休眠当前场景,启动/唤醒目标场景,当前场景状态保留在内存中。
- transition():带 duration 的动画过渡,支持 moveAbove、sleep、remove、allowInput、data、onUpdate 等选项。
并行运行场景
- launch():并行启动另一个场景(不停止当前场景)。
- run():智能启动器,未运行则启动,已暂停则恢复,休眠则唤醒。
- 渲染顺序控制:bringToTop、sendToBack、moveAbove、moveBelow、moveUp、moveDown、swapPosition。
场景间传递数据
- 通过 start/launch/restart/switch/wake/run 传数据,在 init(data) 和 create(data) 中可用。
- 通过 this.sys.getData() 稍后访问 settings.data。
- 全局 registry(所有场景共享):this.registry.set/get。
- 场景专属数据管理器:this.data.set/get。
- 直接场景引用:this.scene.get('OtherScene')。
- 全局 registry 上的事件:this.registry.events.on('changedata-playerHP', ...)。
暂停与恢复
- pause():停止更新循环,仍渲染。
- resume():恢复更新循环。
- sleep():不更新也不渲染,但状态保留。
- wake():从休眠恢复。
- stop():完全关闭,清空显示列表和计时器。
- 状态检查:isActive、isPaused、isSleeping、isVisible。
- 独立控制可见性/活动性:setActive、setVisible。
运行时增删场景
- add():动态添加新场景,参数为 key、sceneConfig、autoStart、data。
- remove():完全移除场景(已销毁,无法重启)。
- 可从同一类生成多个实例。
跨场景事件通信
一个场景发出自定义事件,另一个场景监听,发出方解耦。例如 GameScene 发出 'addScore' 事件,UIScene 通过 this.scene.get('GameScene').events.on('addScore', ...) 监听。
按场景配置插件
- 禁用所有默认插件:super({ key: 'MinimalScene', plugins: [] })。
- 仅包含特定插件:super({ key: 'PreloadScene', plugins: ['Loader'] })。
构造函数中的场景配置
可传入 key、physics、loader、pack 等配置。pack 在 preload() 运行前加载文件,适合进度条资源。
安全重启场景
在 init() 中重置状态,而非构造函数。构造函数只运行一次,init() 每次启动都运行。可在 create() 中通过 this.events.once('shutdown', ...) 清理,避免陈旧引用。
事件
所有事件在 this.events 上发出,通过 this.events.on('eventname', callback) 监听。
生命周期事件:'boot'、'start'、'ready'、'create'、'preupdate'、'update'、'postupdate'、'prerender'、'render'。
状态变更事件:'pause'、'resume'、'sleep'、'wake'、'shutdown'、'destroy'。
过渡事件:'transitionout'、'transitioninit'、'transitionstart'、'transitionwake'、'transitioncomplete'。
游戏对象事件:'addedtoscene'、'removedfromscene'。
适用场景
适用于使用 Phaser 4 开发游戏时需要组织多个场景(如加载场景、菜单场景、游戏场景、UI 场景、暂停菜单等)、管理场景切换与并行运行、在场景间传递数据或通信、以及控制场景暂停/休眠/唤醒等场景。
限制与注意事项
- 操作是排队执行而非立即执行。调用 this.scene.start('X') 不会同步启动 X,而是在下一次 SceneManager 更新时发生,不要在同一帧内依赖目标场景的状态。
- start() 会关闭调用场景。若想两者都运行,使用 launch() 或 run()。
- switch() 休眠,start() 关闭。switch() 将当前场景保留在内存中(休眠),而 start() 触发完全关闭。休眠场景的事件和引用仍然存活。
- 暂停的场景仍会渲染。pause() 只停止更新循环,场景仍被绘制。使用 sleep() 同时停止更新和渲染。
- 不要覆盖 this.sys。Scene 类 JSDoc 明确警告:覆盖 this.sys 会破坏一切。
- 不带 key 的 this.scene.start() 会重启当前场景,等同于 this.scene.restart()。
- 传给 start()/launch() 的数据在 init(data) 和 create(data) 中都可用,存储在 settings.data 中,稍后可通过 this.sys.getData() 访问。
- 休眠场景仍可接收其他场景的事件。若场景 A 休眠但场景 B 在全局 registry 上发出事件,场景 A 的监听器仍会触发,需注意休眠场景上的活动监听器。