恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Phaser DataManager 完整指南:GameObject、Scene 与 Registry 三层键值数据存储与事件驱动状态管理

  • 首页
  • 资讯中心
  • /
  • Phaser DataManager 完整指南:GameObject、Scene 与 Registry 三层键值数据存储与事件驱动状态管理

相关资讯

Hugo Taxonomy 对象方法全解:Alphabetical、ByCount、Count、Get 与 Page 的实战指南 2026/9/19 19:29:13
用 yuzu 模拟器在电脑上跑 Switch 游戏:3 步快速上手 2026/9/19 19:29:13
在 Yew 应用中使用 yew-agent 与 Web Worker 执行后台计算:web_worker_fib 示例深度解析 2026/9/19 19:29:13

最新资讯

CANN SHMEM 之 mte_perftest 参数化性能测试指南:基于 MTE 的 put/get 带宽评测
Front-End-Checklist 空链接与失效链接修复指南:为每个 `<a>` 提供可访问名称
在 OpenDesign 中復刻 GitHub 風格的工程化設計系統:Primer 色彩、14px 資訊密度與 tokens.css 實作剖析
DeskcommCRM落地实战:化解客户信息孤岛,构建高效客户管理
marked 中 GFM 表格后的行内代码解析:nptable 行延续规则与块级中断机制
Excel数据透视表高级技巧与实战应用

今日推荐

oh-my-hermes:打造跨工具的命令编排与插件化工作流
OpenClaw.NET 用 /goal start 跑长任务,模型 Base URL 改到 TaoToken
SYB创业计划书财务逻辑拆解:从销售收入预测到现金流量计划

本周热门

AI SDK Harness 依赖更新指南:掌握 harness 包 SDK 依赖的升级、桥接同步与一致性校验
Refine v5 Ant Design NumberField 组件实战:基于 Intl 的本地化数字格式化
Flutter应用改名全指南:从Android到iOS的配置与工具实践

本月精选

自研推理加速器Redwood:两周内实现PyTorch模型高效部署的实战教程
V4L2摄像头采集实战:从camera_client.rar到出图全流程解析
从“谁发明了钢琴键”到知识问答智能体:RAG与记忆工程实践

Phaser DataManager 完整指南:GameObject、Scene 与 Registry 三层键值数据存储与事件驱动状态管理

发布时间:2026/9/19 19:34:13
Phaser DataManager 完整指南:GameObject、Scene 与 Registry 三层键值数据存储与事件驱动状态管理 Phaser DataManager 完整指南GameObject、Scene 与 Registry 三层键值数据存储与事件驱动状态管理【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser本文以 Phaser 仓库中skills/data-manager/SKILL.md为骨架结合 DataManager 核心实现、Scene 数据插件、GameObject 便捷方法 等源码与测试系统讲解 Phaser 的键值数据存储体系。读完你将掌握如何在任意 GameObject 上挂载自定义数据setData/getData、如何用this.data管理单场景状态、如何用this.registry实现跨场景共享的全局状态以及如何基于setdata/changedata/removedata事件构建解耦的响应式数据流并用merge、query、freeze等工具实现存档读写、批量查询与数据保护。Phaser 的 DataManager 提供带事件驱动变更跟踪的键值存储运行在三个层级每 GameObjectsprite.setData/getData、每 Scenethis.data与全局this.registry。每一次 set/change/remove 操作都会发出事件让游戏系统之间可以无需紧耦合即可完成响应式数据绑定。这套机制常被用于血条/金币等 UI 与玩法数据的联动、跨场景的全局存档状态、以及实体身上自定义属性的临时存储。快速开始以下代码覆盖三层数据存储的最小用法this均指当前 Scene// 每 GameObject 数据首次使用时自动创建 DataManager const gem this.add.sprite(100, 100, gem); gem.setData(value, 50); gem.setData({ color: red, level: 2 }); gem.getData(value); // 50 gem.getData([value, color]); // [50, red] // 自增 / 翻转辅助方法 gem.incData(value, 10); // value 现在是 60 gem.incData(value, -5); // value 现在是 55传负数即为递减 gem.toggleData(active); // false - true未设置时从 false 开始 // Scene 级数据this.data 是 DataManagerPlugin this.data.set(score, 0); this.data.get(score); // 0 this.data.values.score 100; // 触发 changedata 事件 // 全局 Registry所有 Scene 共享 this.registry.set(highScore, 9999); // 任何 Scene 都能读取 this.registry.get(highScore); // 9999核心概念三层数据存储架构DataManager 的三种挂载位置决定了数据的作用域与事件发射目标选择哪种取决于数据需要存活多久、被谁访问。DataManager 基类Phaser.Data.DataManager基类负责把键值对存进内部list对象并提供一套完整的读写与事件 API源码见 src/data/DataManager.jsset(key, value)—— 存储一个值如果是新键会发setdata如果是已存在的键会发changedatachangedata-{key}。也接受一个对象批量设置多个键。get(key)—— 获取一个值传入键名数组则返回对应值的数组。inc(key, amount)—— 数值自增默认1。键不存在时先从 0 开始创建对应源码 inc 实现。toggle(key)—— 翻转布尔值。键不存在时先从false创建再翻转为true对应源码 toggle 实现。remove(key)—— 删除键发removedata事件接受键名数组对应源码 remove/removeValue 实现。has(key)—— 返回该键是否存在基于list.hasOwnProperty见 has 实现。getAll()—— 返回全部键值对的浅拷贝每次调用都生成新对象见 getAll 实现。query(regex)—— 返回所有键名匹配给定正则的条目见 query 实现。each(callback, context, ...args)—— 遍历所有条目。回调签名为(parent, key, value, ...args)见 each 实现。merge(data, overwrite)—— 从对象批量导入。overwrite默认true设为false则跳过已存在的键见 merge 实现。pop(key)—— 一步完成取出并删除发removedata事件见 pop 实现。reset()—— 清空全部数据并解除冻结不发任何事件见 reset 实现。freeze/setFreeze(bool)—— 冻结后所有 set/remove/inc/toggle 操作静默无效no-op见 setFreeze 与 freeze 存取器。count—— 只读属性返回已存储条目的数量见 count 实现。values是一个代理对象允许直接通过属性读写并自动触发事件// 先 set(gold, 100)然后可以 data.values.gold 50; // 触发 changedata 与 changedata-gold // 但创建新键必须走 set() —— 直接对 values 赋值新属性 // 不会建立事件代理只会创建一个静默的普通属性。这一机制在源码中非常直观setValue在键首次创建时通过Object.defineProperty为values定义 getter/settersetter 内部写入list[key]并发射changedata与changedata-{key}事件见 setValue 实现而已存在的键走 setter 路径即可触发事件。因此必须先set创建键才能通过values修改并得到事件反馈。Scene 数据插件Phaser.Data.DataManagerPluginDataManagerPlugin继承自DataManager作为名为data的场景插件注册见 PluginCache.register任何 Scene 内可通过this.data访问。它使用 Scene 的事件发射器scene.sys.events因此数据事件在 Scene 的事件总线上触发源码见 DataManagerPlugin 构造// 在 Scene 的 create() 中 this.data.set(lives, 3); // 在 Scene 的事件发射器上监听 this.events.on(changedata-lives, (scene, value, previousValue) { console.log(Lives changed from, previousValue, to, value); });插件在场景关闭shutdown时会自动移除自身的 shutdown 监听见 shutdown 实现在场景销毁destroy时完整销毁见 destroy 实现。需要特别留意的是shutdown 不会清空数据——数据在场景重启后依然保留只有场景 destroy 才会彻底重置下文易错点中有对应的手动清理方案。Registry全局数据存储Registry 是挂在Game对象上的一个普通DataManager实例game.registry它拥有独立的EventEmitter不与其他场景共享。在 src/core/Game.js 中可以确认this.registry new DataManager(this, new EventEmitter());每个 Scene 通过注入映射拿到this.registry引用见 src/scene/Scene.js// Scene A 设置全局数据 this.registry.set(currentLevel, 1); // Scene B 读取它 const level this.registry.get(currentLevel); // 监听 registry 变化注意事件发在 registry.events 上而不是 this.events this.registry.events.on(changedata-currentLevel, (game, value, previousValue) { console.log(Level changed to, value); });Registry 与 Game 同生命周期场景重启或关闭都不会自动清空它因此它是跨场景共享状态的默认选择。每 GameObject 数据GameObject默认没有 DataManager而是在首次调用setData()、getData()、incData()或toggleData()时惰性创建也可以显式调用setDataEnabled()提前创建源码见 setDataEnabled四个便捷方法在 setData、incData、toggleData、getData 中均以if (!this.data) this.data new DataManager(this);完成惰性创建。由于 GameObject 本身继承自 EventEmitterDataManager 的事件发射器就是 GameObject 自身因此数据事件直接发在游戏对象上const player this.add.sprite(0, 0, player); player.setData(hp, 100); // 直接在游戏对象上监听 player.on(changedata-hp, (gameObject, value, previousValue) { if (value 0) { gameObject.destroy(); } });常见实战模式设置与读取数据// 单个键 sprite.setData(speed, 200); sprite.getData(speed); // 200 // 一次设置多个键对象形式 sprite.setData({ speed: 200, direction: left, hp: 100 }); // 批量读取 解构 const [speed, hp] sprite.getData([speed, hp]); // 直接通过 values 读写必须先 set 过 sprite.data.values.speed 300; // 触发 changedata 事件 const s sprite.data.values.speed; // 300监听变化// 监听游戏对象上任何数据变化 sprite.on(changedata, (gameObject, key, value, previousValue) { console.log(key, changed to, value); }); // 监听特定键的变化推荐更高效 sprite.on(changedata-hp, (gameObject, value, previousValue) { this.hpBar.setValue(value); }); // 监听新数据首次设置 sprite.on(setdata, (gameObject, key, value) { console.log(New data key:, key); }); // 监听数据被移除 sprite.on(removedata, (gameObject, key, value) { console.log(Removed:, key, was, value); });全局 Registry 实现跨场景状态典型场景HUD 场景监听 Game 场景写入的分数。// HUDScene.create() 中 this.registry.events.on(changedata-score, (game, value) { this.scoreText.setText(Score: value); }); this.events.once(shutdown, () { this.registry.events.off(changedata-score); }); // GameScene.update() 中 this.registry.set(score, this.score);复杂数据与对象// 可以存储任意值类型数字、字符串、布尔、对象、数组 sprite.setData(inventory, [sword, shield]); sprite.setData(stats, { str: 10, dex: 8, int: 12 }); // 注意原地修改已存储的对象/数组不会触发 changedata const inv sprite.getData(inventory); inv.push(potion); // 没有事件触发因为引用没有变化。 // 要触发事件需要重新 set 该键 sprite.setData(inventory, [...inv]); // 新数组引用才会触发 changedata合并数据merge// 合并默认值——只设置尚不存在的键 sprite.data.merge({ hp: 100, speed: 200, armor: 0 }, false); // 合并并覆盖已有值 sprite.data.merge(savedState, true);从源码看merge内部对每个键走setValue路径见 merge 实现因此新键会发setdata、被覆盖的键会发changedata非常适合存档恢复场景。按模式查询数据query// 找出所有匹配正则的键 this.data.set(enemy_1_hp, 50); this.data.set(enemy_2_hp, 80); this.data.set(player_hp, 100); const enemyData this.data.query(/^enemy_/); // { enemy_1_hp: 50, enemy_2_hp: 80 }冻结数据freeze// 阻止一切修改set、remove、inc、toggle 全部变成 no-op sprite.data.freeze true; sprite.setData(hp, 0); // 被静默忽略 sprite.data.freeze false; sprite.setData(hp, 0); // 恢复生效 // 也可以用可链式调用的方法 sprite.data.setFreeze(true);数据持久化模式配合getAll()与merge()即可快速实现 localStorage 存档// 保存到 localStorage function saveGame(scene) { const state scene.data.getAll(); localStorage.setItem(saveData, JSON.stringify(state)); } // 从 localStorage 恢复 function loadGame(scene) { const raw localStorage.getItem(saveData); if (raw) { scene.data.merge(JSON.parse(raw), true); } }事件体系所有数据事件常量定义在Phaser.Data.Events下见 src/data/events/index.js。发射器取决于 DataManager 的挂载位置GameObject 上事件发在对象自身Scene 数据发在scene.sys.eventsRegistry 发在registry.events。常量字符串触发时机回调参数SET_DATAsetdata创建新键时(parent, key, value)CHANGE_DATAchangedata已存在键的值改变时(parent, key, value, previousValue)CHANGE_DATA_KEYchangedata-特定键改变时后面拼接键名(parent, value, previousValue)REMOVE_DATAremovedata键被移除时(parent, key, value)DESTROYdestroyDataManager 的父对象被销毁时无parent参数是 DataManager 的持有者GameObject、Scene 或 Game 实例。需要强调CHANGE_DATA_KEY是一个前缀实际事件字符串是changedata- 键名。例如设置名为score的键会发出changedata-score。各事件常量文件位于 src/data/events/ 目录例如 CHANGE_DATA_EVENT.js 中明确注释游戏对象启用数据后可用sprite.on(changedata, listener)监听且该事件对所有变更项触发监听特定项请用CHANGE_DATA_KEY_EVENT。API 速查表GameObject 便捷方法方法返回说明setDataEnabled()this显式创建 DataManager通常自动创建setData(key, value)this设置单个键或传入对象批量设置getData(key)*获取单个值或传入数组批量获取incData(key, amount?)this数值自增默认 1传负数递减toggleData(key)this翻转布尔值DataManager 方法方法返回说明set(key, value)this设置单个键或对象形式的键值对get(key)*获取值——支持字符串或字符串数组getAll()object所有条目的浅拷贝query(regex)object键名匹配 RegExp 的所有条目each(cb, ctx, ...args)this遍历所有条目merge(data, overwrite?)this批量导入overwrite默认trueremove(key)this删除键——支持字符串或数组pop(key)*取出并一步删除has(key)boolean检查键是否存在inc(key, amount?)this自增默认 1toggle(key)this翻转布尔值setFreeze(bool)this冻结/解冻修改reset()this清空所有数据并解除冻结countnumber只读条目计数freezeboolean读写冻结状态valuesobject直接属性访问的代理对象get()与values副本 vs 实时引用理解两者的区别是正确更新数据的关键// get() 对基本类型返回副本——修改局部变量不会更新 DataManager let score this.data.get(score); score 10; // 只改本地副本DataManager 里仍是旧值 // values 提供实时代理——赋值会触发 CHANGE_DATA 事件 this.data.values.score 10; // 既更新 DataManager 又触发 changedata-score // 对对象而言get() 返回的是存储的引用不是深拷贝 const stats this.data.get(stats); stats.hp - 10; // 修改了存储对象但不会触发事件 this.data.set(stats, { ...stats }); // 用新引用重新 set 才能触发事件事件发射路由数据事件发往何处完全取决于 DataManager 所在的位置DataManager 持有者事件发射目标示例监听GameObjectGameObject 自身sprite.on(changedata-hp, ...)Scenethis.dataScene 事件总线this.eventsthis.events.on(changedata-score, ...)Registrythis.registryRegistry 自己的发射器this.registry.events.on(changedata-score, ...)键特定事件changedata-{key}只在该键变化时触发而通用事件changedata对每个键的变化都会触发。性能上始终优先使用键特定监听器。易错点清单键名大小写敏感gold和Gold是两个不同的键。命名规范要保持一致源码注释 set 的文档 与 has 的文档 均明确说明这一点。values 代理必须先 set()必须先调用set(key, value)创建键之后才能通过data.values.key修改。对全新键直接给values赋值不会建立事件代理——只会创建一个不发任何事件的普通属性见 values 说明。原地修改对象/数组不触发事件原地修改已存储的对象或数组不会发changedata因为引用没有变化。必须用新引用重新set才能触发事件。Registry 监听器跨场景重启存活Registry 活在 Game 对象上。添加到this.registry.events的监听器在场景重启时不会被清理务必在SHUTDOWN时手动移除create() { const handler (game, value) { this.updateHUD(value); }; this.registry.events.on(changedata-score, handler); this.events.once(shutdown, () { this.registry.events.off(changedata-score, handler); }); }冻结的 DataManager 静默失败当freeze为true时所有写操作set、remove、inc、toggle、pop、merge都静默无操作既不抛错也不发事件源码中 set、inc、toggle、remove 均以if (this._frozen) return this;开头。如果忘记自己冻结过数据很容易困惑。Scene 数据插件的 shutdown 与 destroy 区别DataManagerPlugin在 shutdown 时只移除自己的 shutdown 监听不清空数据见 shutdown 实现场景重启后数据依然存在只有场景 destroy 才会彻底重置。若需要在重启时清空手动在 shutdown 监听里 resetthis.events.once(shutdown, () { this.data.reset(); });inc()作用于非数值inc()内部使用运算符见 inc 实现。对字符串会做拼接而非数值相加对布尔值会先隐式转为 0 或 1 再自增。只对确定存数值的键使用inc()。reset()不触发任何事件reset()静默清空所有数据——被删除的键不会发removedata见 reset 实现。如果每个键都需要移除事件请逐个调用remove()。冻结会打断批量操作setFreeze(true)立即生效。如果在连续set()的中途冻结批次中后续调用会静默 no-op。务必在所有写入完成后再冻结。getAll()返回的是快照getAll()每次返回一个新的普通对象见 getAll 实现。它是浅拷贝——基本类型独立但对象/数组值仍与 DataManager 内部存储共享引用。changedata-key 回调的第一个参数通用changedata事件回调收到(parent, key, value, previousValue)键特定changedata-{key}事件会省略key参数回调为(parent, value, previousValue)。这个差异很容易被忽略从 事件常量定义 与setValue的两次emit调用setValue 实现可以对照验证。源码地图路径说明src/data/DataManager.jsDataManager 核心类——set、get、each、merge、remove、query、freeze、事件发射src/data/DataManagerPlugin.js继承 DataManager 的场景插件注册为this.datasrc/data/events/index.js事件常量导出CHANGE_DATA、SET_DATA、REMOVE_DATA、CHANGE_DATA_KEY、DESTROYsrc/data/events/SET_DATA_EVENT.jssetdata——创建新键时发出src/data/events/CHANGE_DATA_EVENT.jschangedata——已存在键的值变化时发出src/data/events/CHANGE_DATA_KEY_EVENT.jschangedata-——逐键变化事件前缀src/data/events/REMOVE_DATA_EVENT.jsremovedata——键被移除时发出src/data/events/DESTROY_EVENT.jsdestroy——DataManager 监听其父对象的销毁事件src/gameobjects/GameObject.jssetData、getData、incData、toggleData、setDataEnabled 便捷方法src/core/Game.js创建game.registry——全局 DataManager 实例src/scene/Scene.js向场景暴露this.registry从 Game 注入与this.dataDataManagerPlugin测试验证与延伸阅读仓库的测试目录为上述行为提供了完整佐证tests/data/DataManager.test.js 覆盖了构造器的多种 eventEmitter 回退、get/getAll/query、set的setdata/changedata事件、inc的默认值与负数、toggle对 undefined 的处理、each的参数传递、merge的覆盖语义以及冻结时的静默行为tests/data/DataManagerPlugin.test.js 则验证插件在场景生命周期中的 shutdown/destroy 行为。若想进一步串联数据驱动与其他系统可继续阅读仓库中的 场景管理指南 与 事件系统指南——DataManager 的事件发射正是构建在 Phaser 的 EventEmitter 之上的。掌握三层数据存储与事件路由规则后你便可以在不耦合系统的情况下为游戏搭建出清晰、可追踪、可持久化的状态管理方案。【免费下载链接】phaserPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.项目地址: https://gitcode.com/gh_mirrors/ph/phaser创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号