data-manager

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

DataManager

DataManager

Phaser's DataManager provides key-value storage with event-driven change tracking. It operates at three levels: per-GameObject (
sprite.setData
/
getData
), per-Scene (
this.data
), and global (
this.registry
). Every set/change/remove operation emits events, enabling reactive data binding between game systems without tight coupling.
Key source paths:
src/data/DataManager.js
,
src/data/DataManagerPlugin.js
,
src/data/events/
,
src/gameobjects/GameObject.js
(setData/getData/incData/toggleData) Related skills: ../scenes/SKILL.md, ../events-system/SKILL.md
Phaser的DataManager提供带事件驱动变更追踪的键值存储功能。它在三个层级运作:每个GameObject(
sprite.setData
/
getData
)、每个Scene(
this.data
)以及全局层级(
this.registry
)。每一次设置/变更/移除操作都会触发事件,实现游戏系统间的响应式数据绑定,无需紧密耦合。
核心源码路径:
src/data/DataManager.js
src/data/DataManagerPlugin.js
src/data/events/
src/gameobjects/GameObject.js
(setData/getData/incData/toggleData) 相关技能: ../scenes/SKILL.md、../events-system/SKILL.md

Quick Start

快速开始

js
// Per-GameObject data (auto-creates DataManager on first use)
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']

// Increment / toggle helpers
gem.incData('value', 10);       // value is now 60
gem.incData('value', -5);       // value is now 55 (negative to decrement)
gem.toggleData('active');        // false -> true (starts from false if unset)

// Scene-level data (this.data is a DataManagerPlugin)
this.data.set('score', 0);
this.data.get('score');          // 0
this.data.values.score += 100;   // triggers changedata event

// Global registry (shared across ALL scenes)
this.registry.set('highScore', 9999);
// Any scene can read it:
this.registry.get('highScore');  // 9999
js
// 单个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开始)

// 场景级数据(this.data是DataManagerPlugin实例)
this.data.set('score', 0);
this.data.get('score');          // 0
this.data.values.score += 100;   // 触发changedata事件

// 全局注册表(所有场景共享)
this.registry.set('highScore', 9999);
// 任意场景都可以读取:
this.registry.get('highScore');  // 9999

Core Concepts

核心概念

DataManager (
Phaser.Data.DataManager
)

DataManager(
Phaser.Data.DataManager

The base class that stores key-value pairs in an internal
list
object. It provides:
  • set(key, value)
    -- stores a value; emits
    setdata
    (new key) or
    changedata
    +
    changedata-{key}
    (existing key). Accepts an object to set multiple keys at once.
  • get(key)
    -- retrieves a value, or pass an array of keys to get an array of values.
  • inc(key, amount)
    -- increments a numeric value (defaults to +1). Creates from 0 if key does not exist.
  • toggle(key)
    -- flips a boolean value. Creates from
    false
    if key does not exist.
  • remove(key)
    -- deletes a key; emits
    removedata
    . Accepts an array of keys.
  • has(key)
    -- returns
    true
    if the key exists.
  • getAll()
    -- returns a shallow copy of all key-value pairs as a plain object.
  • query(regex)
    -- returns all entries whose keys match the given RegExp.
  • each(callback, context, ...args)
    -- iterates all entries. Callback signature:
    (parent, key, value, ...args)
    .
  • merge(data, overwrite)
    -- bulk-imports from an object.
    overwrite
    defaults to
    true
    ; set
    false
    to skip existing keys.
  • pop(key)
    -- retrieves and deletes a key in one call; emits
    removedata
    .
  • reset()
    -- clears all data and unfreezes.
  • freeze
    /
    setFreeze(bool)
    -- when frozen, all set/remove/inc/toggle operations silently no-op.
  • count
    -- read-only property returning the number of stored entries.
The
values
proxy object allows direct property access with event emission:
js
// After set('gold', 100), you can do:
data.values.gold += 50; // emits changedata and changedata-gold
// But you MUST use set() to create a key first -- direct assignment
// to values for a new key will NOT set up the event proxy.
基础类,在内部
list
对象中存储键值对。它提供以下功能:
  • set(key, value)
    -- 存储一个值;当是新键时触发
    setdata
    事件,当是已有键时触发
    changedata
    changedata-{key}
    事件。支持传入对象一次性设置多个键。
  • get(key)
    -- 获取一个值,或传入键数组获取对应值的数组。
  • inc(key, amount)
    -- 递增数值(默认+1)。若键不存在则从0开始创建。
  • toggle(key)
    -- 翻转布尔值。若键不存在则从
    false
    开始创建。
  • remove(key)
    -- 删除一个键;触发
    removedata
    事件。支持传入键数组批量删除。
  • has(key)
    -- 若键存在则返回
    true
  • getAll()
    -- 返回所有键值对的浅拷贝普通对象。
  • query(regex)
    -- 返回所有键匹配给定正则表达式的条目。
  • each(callback, context, ...args)
    -- 遍历所有条目。回调签名:
    (parent, key, value, ...args)
  • merge(data, overwrite)
    -- 从对象批量导入数据。
    overwrite
    默认为
    true
    ;设为
    false
    则跳过已有键。
  • pop(key)
    -- 一次性完成获取并删除键的操作;触发
    removedata
    事件。
  • reset()
    -- 清空所有数据并解除冻结。
  • freeze
    /
    setFreeze(bool)
    -- 冻结状态下,所有设置/移除/增量/切换操作都会静默失效。
  • count
    -- 只读属性,返回存储条目的数量。
values
代理对象允许直接访问属性并触发事件:
js
// 设置('gold', 100)之后,你可以这样操作:
data.values.gold += 50; // 触发changedata和changedata-gold事件
// 但你必须先调用set()创建键——直接给values的新键赋值不会建立事件代理。

Scene Data Plugin (
Phaser.Data.DataManagerPlugin
)

场景数据插件(
Phaser.Data.DataManagerPlugin

Extends DataManager. Registered as the
data
scene plugin, accessible as
this.data
in any Scene. It uses the Scene's event emitter (
scene.sys.events
), so data events fire on the Scene's event bus.
js
// In a Scene's create():
this.data.set('lives', 3);

// Listen on the scene's event emitter
this.events.on('changedata-lives', (scene, value, previousValue) => {
    console.log('Lives changed from', previousValue, 'to', value);
});
The plugin auto-cleans on scene shutdown (removes its shutdown listener) and fully destroys on scene destroy.
继承自DataManager。注册为场景插件
data
,在任意Scene中可通过
this.data
访问。它使用Scene的事件发射器(
scene.sys.events
),因此数据事件会在Scene的事件总线上触发。
js
// 在Scene的create()方法中:
this.data.set('lives', 3);

// 监听场景的事件发射器
this.events.on('changedata-lives', (scene, value, previousValue) => {
    console.log('生命值从', previousValue, '变为', value);
});
该插件会在场景关闭时自动清理(移除关闭监听器),并在场景销毁时完全销毁。

Registry (Global Data Store)

注册表(全局数据存储)

The registry is a plain
DataManager
instance on the
Game
object (
game.registry
). It has its own dedicated
EventEmitter
(not shared with any scene). Every scene gets a reference as
this.registry
via the injection map.
js
// Scene A sets global data
this.registry.set('currentLevel', 1);

// Scene B reads it
const level = this.registry.get('currentLevel');

// Listen for registry changes (note: events fire on registry.events, NOT this.events)
this.registry.events.on('changedata-currentLevel', (game, value, previousValue) => {
    console.log('Level changed to', value);
});
The registry persists for the lifetime of the Game. It is never automatically cleared on scene restart or shutdown.
注册表是
Game
对象上的一个普通DataManager实例(
game.registry
)。它有自己专属的
EventEmitter
(不与任何场景共享)。每个场景通过注入映射获取引用
this.registry
js
// 场景A设置全局数据
this.registry.set('currentLevel', 1);

// 场景B读取数据
const level = this.registry.get('currentLevel');

// 监听注册表变更(注意:事件在registry.events上触发,而非this.events)
this.registry.events.on('changedata-currentLevel', (game, value, previousValue) => {
    console.log('关卡变为', value);
});
注册表在Game的生命周期内持续存在,不会在场景重启或关闭时自动清空。

Per-GameObject Data

单个GameObject的数据

GameObjects do NOT have a DataManager by default. It is created lazily on first call to
setData()
,
getData()
,
incData()
, or
toggleData()
. You can also explicitly call
setDataEnabled()
.
The DataManager's event emitter is the GameObject itself (which extends EventEmitter), so data events fire directly on the GameObject:
js
const player = this.add.sprite(0, 0, 'player');
player.setData('hp', 100);

// Listen directly on the game object
player.on('changedata-hp', (gameObject, value, previousValue) => {
    if (value <= 0) {
        gameObject.destroy();
    }
});
GameObject默认没有DataManager。首次调用
setData()
getData()
incData()
toggleData()
时会延迟创建。你也可以显式调用
setDataEnabled()
来创建。
DataManager的事件发射器就是GameObject本身(它继承自EventEmitter),因此数据事件会直接在GameObject上触发:
js
const player = this.add.sprite(0, 0, 'player');
player.setData('hp', 100);

// 直接在游戏对象上监听
player.on('changedata-hp', (gameObject, value, previousValue) => {
    if (value <= 0) {
        gameObject.destroy();
    }
});

Common Patterns

常见模式

Setting and Getting Data

设置与获取数据

js
// Single key
sprite.setData('speed', 200);
sprite.getData('speed'); // 200

// Multiple keys at once (object form)
sprite.setData({ speed: 200, direction: 'left', hp: 100 });

// Batch get with destructuring
const [speed, hp] = sprite.getData(['speed', 'hp']);

// Direct values access (read and write after initial set)
sprite.data.values.speed = 300; // emits changedata event
const s = sprite.data.values.speed; // 300
js
// 单个键
sprite.setData('speed', 200);
sprite.getData('speed'); // 200

// 一次性设置多个键(对象形式)
sprite.setData({ speed: 200, direction: 'left', hp: 100 });

// 批量获取并解构
const [speed, hp] = sprite.getData(['speed', 'hp']);

// 直接访问values(初始设置后可读写)
sprite.data.values.speed = 300; // 触发changedata事件
const s = sprite.data.values.speed; // 300

Listening for Changes

监听变更

js
// Listen for ANY data change on a game object
sprite.on('changedata', (gameObject, key, value, previousValue) => {
    console.log(key, 'changed to', value);
});

// Listen for a SPECIFIC key change (preferred -- more efficient)
sprite.on('changedata-hp', (gameObject, value, previousValue) => {
    this.hpBar.setValue(value);
});

// Listen for new data being set (first time only)
sprite.on('setdata', (gameObject, key, value) => {
    console.log('New data key:', key);
});

// Listen for data removal
sprite.on('removedata', (gameObject, key, value) => {
    console.log('Removed:', key, 'was', value);
});
js
// 监听游戏对象上的任意数据变更
sprite.on('changedata', (gameObject, key, value, previousValue) => {
    console.log(key, '变为', value);
});

// 监听特定键的变更(推荐——效率更高)
sprite.on('changedata-hp', (gameObject, value, previousValue) => {
    this.hpBar.setValue(value);
});

// 监听新数据的设置(仅首次触发)
sprite.on('setdata', (gameObject, key, value) => {
    console.log('新数据键:', key);
});

// 监听数据移除
sprite.on('removedata', (gameObject, key, value) => {
    console.log('已移除:', key, '值为', value);
});

Global Registry for Cross-Scene State

跨场景状态的全局注册表

js
// HUD scene watches for score changes set by the Game scene
// In 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');
});

// In GameScene.update():
this.registry.set('score', this.score);
js
// HUD场景监听Game场景设置的分数变更
// 在HUDScene.create()中:
this.registry.events.on('changedata-score', (game, value) => {
    this.scoreText.setText('分数:' + value);
});
this.events.once('shutdown', () => {
    this.registry.events.off('changedata-score');
});

// 在GameScene.update()中:
this.registry.set('score', this.score);

Complex Data and Objects

复杂数据与对象

js
// You can store any value type: numbers, strings, booleans, objects, arrays
sprite.setData('inventory', ['sword', 'shield']);
sprite.setData('stats', { str: 10, dex: 8, int: 12 });

// CAUTION: mutating a stored object/array does NOT trigger changedata
const inv = sprite.getData('inventory');
inv.push('potion');
// No event fired! The reference didn't change.

// To trigger the event, re-set the key:
sprite.setData('inventory', [...inv]); // new array reference triggers changedata
js
// 你可以存储任意类型的值:数字、字符串、布尔值、对象、数组
sprite.setData('inventory', ['sword', 'shield']);
sprite.setData('stats', { str: 10, dex: 8, int: 12 });

// 注意:修改存储的对象/数组不会触发changedata事件
const inv = sprite.getData('inventory');
inv.push('potion');
// 不会触发事件!因为引用没有改变。

// 要触发事件,需重新设置该键:
sprite.setData('inventory', [...inv]); // 新数组引用会触发changedata事件

Merging Data

合并数据

js
// Merge defaults -- only sets keys that don't already exist
sprite.data.merge({ hp: 100, speed: 200, armor: 0 }, false);

// Merge and overwrite existing values
sprite.data.merge(savedState, true);
js
// 合并默认值——仅设置不存在的键
sprite.data.merge({ hp: 100, speed: 200, armor: 0 }, false);

// 合并并覆盖已有值
sprite.data.merge(savedState, true);

Querying Data by Pattern

按模式查询数据

js
// Find all keys matching a regex
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 }
js
// 查找所有匹配正则的键
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 }

Freezing Data

冻结数据

js
// Prevent all modifications (set, remove, inc, toggle all become no-ops)
sprite.data.freeze = true;
sprite.setData('hp', 0); // silently ignored
sprite.data.freeze = false;
sprite.setData('hp', 0); // works again

// Also available as a chainable method
sprite.data.setFreeze(true);
js
// 禁止所有修改操作(set、remove、inc、toggle均失效)
sprite.data.freeze = true;
sprite.setData('hp', 0); // 静默忽略
sprite.data.freeze = false;
sprite.setData('hp', 0); // 恢复生效

// 也可使用链式方法
sprite.data.setFreeze(true);

Data Persistence Pattern

数据持久化模式

js
// Save to localStorage
function saveGame(scene) {
    const state = scene.data.getAll();
    localStorage.setItem('saveData', JSON.stringify(state));
}

// Restore from localStorage
function loadGame(scene) {
    const raw = localStorage.getItem('saveData');
    if (raw) {
        scene.data.merge(JSON.parse(raw), true);
    }
}
js
// 保存到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);
    }
}

Events

事件

All data events are defined in
Phaser.Data.Events
. The emitter depends on context: for GameObjects it is the GameObject itself; for scene data it is
scene.sys.events
; for the registry it is
registry.events
.
ConstantStringFired WhenCallback Args
SET_DATA
'setdata'
A new key is created
(parent, key, value)
CHANGE_DATA
'changedata'
An existing key's value changes
(parent, key, value, previousValue)
CHANGE_DATA_KEY
'changedata-'
Specific key changes (append key name)
(parent, value, previousValue)
REMOVE_DATA
'removedata'
A key is removed
(parent, key, value)
DESTROY
'destroy'
DataManager's parent is destroyed(none)
The
parent
argument is the owner of the DataManager (the GameObject, Scene, or Game instance).
Note:
CHANGE_DATA_KEY
is a prefix. The actual event string is
'changedata-'
+ the key name. For example, setting a key called
score
emits
'changedata-score'
.
所有数据事件都定义在
Phaser.Data.Events
中。事件发射器取决于上下文:GameObject的事件发射器是其本身;场景数据的事件发射器是
scene.sys.events
;注册表的事件发射器是
registry.events
常量字符串触发时机回调参数
SET_DATA
'setdata'
创建新键时
(parent, key, value)
CHANGE_DATA
'changedata'
已有键的值变更时
(parent, key, value, previousValue)
CHANGE_DATA_KEY
'changedata-'
特定键变更时(需追加键名)
(parent, value, previousValue)
REMOVE_DATA
'removedata'
键被移除时
(parent, key, value)
DESTROY
'destroy'
DataManager的父对象被销毁时
parent
参数是DataManager的所有者(GameObject、Scene或Game实例)。
注意:
CHANGE_DATA_KEY
是前缀,实际事件字符串为
'changedata-'
+ 键名。例如,设置名为
score
的键会触发
'changedata-score'
事件。

API Quick Reference

API快速参考

GameObject Convenience Methods

GameObject便捷方法

MethodReturnsDescription
setDataEnabled()
this
Explicitly creates the DataManager (normally auto-created)
setData(key, value)
this
Set one key or pass an object for multiple
getData(key)
*
Get one value or pass an array for multiple
incData(key, amount?)
this
Increment numeric value (default +1, negative to decrement)
toggleData(key)
this
Toggle boolean value
方法返回值描述
setDataEnabled()
this
显式创建DataManager(通常会自动创建)
setData(key, value)
this
设置单个键,或传入对象设置多个键
getData(key)
*
获取单个值,或传入数组获取多个值
incData(key, amount?)
this
递增数值(默认+1,负数表示递减)
toggleData(key)
this
翻转布尔值

DataManager Methods

DataManager方法

MethodReturnsDescription
set(key, value)
this
Set single key or object of key-value pairs
get(key)
*
Get value(s) -- string or array of strings
getAll()
object
Shallow copy of all entries
query(regex)
object
All entries with keys matching the RegExp
each(cb, ctx, ...args)
this
Iterate all entries
merge(data, overwrite?)
this
Bulk import; overwrite defaults to
true
remove(key)
this
Delete key(s) -- string or array
pop(key)
*
Get and delete in one call
has(key)
boolean
Check if key exists
inc(key, amount?)
this
Increment (default +1)
toggle(key)
this
Toggle boolean
setFreeze(bool)
this
Freeze/unfreeze modifications
reset()
this
Clear all data and unfreeze
count
number
Read-only entry count
freeze
boolean
Get/set frozen state
values
object
Proxy object for direct property access
方法返回值描述
set(key, value)
this
设置单个键或键值对对象
get(key)
*
获取值——字符串或字符串数组
getAll()
object
所有条目的浅拷贝
query(regex)
object
所有键匹配正则表达式的条目
each(cb, ctx, ...args)
this
遍历所有条目
merge(data, overwrite?)
this
批量导入;overwrite默认为
true
remove(key)
this
删除键——字符串或数组
pop(key)
*
一次性完成获取并删除操作
has(key)
boolean
检查键是否存在
inc(key, amount?)
this
递增(默认+1)
toggle(key)
this
翻转布尔值
setFreeze(bool)
this
冻结/解除冻结修改操作
reset()
this
清空所有数据并解除冻结
count
number
只读条目数量
freeze
boolean
获取/设置冻结状态
values
object
用于直接属性访问的代理对象

get()
vs
values
-- Copies vs Live References

get()
vs
values
—— 拷贝与实时引用

Understanding the difference between
get()
and
values
is critical for correct data updates:
js
// get() returns a copy for primitives -- modifying the local variable does NOT update the DataManager
let score = this.data.get('score');
score += 10;  // local copy only, DataManager still has the old value

// values provides a live proxy -- assignment triggers CHANGE_DATA event
this.data.values.score += 10;  // updates the DataManager AND emits changedata-score

// For objects, get() returns the stored reference (not a deep copy)
const stats = this.data.get('stats');
stats.hp -= 10; // mutates the stored object but does NOT trigger events
this.data.set('stats', { ...stats }); // re-set with new reference to trigger event
理解
get()
values
的区别对正确更新数据至关重要:
js
// 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 }); // 用新引用重新设置以触发事件

Event Emitter Routing

事件发射器路由

Data events emit on different targets depending on where the DataManager lives:
DataManager OwnerEvents Emit OnExample Listener
GameObjectThe GameObject itself
sprite.on('changedata-hp', ...)
Scene (
this.data
)
Scene event bus (
this.events
)
this.events.on('changedata-score', ...)
Registry (
this.registry
)
Registry's own emitter
this.registry.events.on('changedata-score', ...)
The key-specific event
'changedata-{key}'
fires only for that exact key, while the generic
'changedata'
fires for every key change. Always prefer key-specific listeners for performance.
数据事件的触发目标取决于DataManager所在位置:
DataManager所有者事件触发位置监听示例
GameObjectGameObject本身
sprite.on('changedata-hp', ...)
Scene(
this.data
场景事件总线(
this.events
this.events.on('changedata-score', ...)
注册表(
this.registry
注册表自身的发射器
this.registry.events.on('changedata-score', ...)
特定键事件
'changedata-{key}'
仅针对该键触发,而通用
'changedata'
事件会在所有键变更时触发。为了性能,优先使用特定键监听器。

Gotchas

注意事项

Keys Are Case-Sensitive

键名区分大小写

'gold'
and
'Gold'
are two different keys. Be consistent with naming conventions.
'gold'
'Gold'
是两个不同的键,请保持命名规范一致。

values Proxy Requires set() First

values代理需先调用set()

You must call
set(key, value)
to create a key before modifying it via
data.values.key
. Direct assignment to
values
for a brand-new key will NOT create the event proxy -- it creates a plain property that emits no events.
你必须先调用
set(key, value)
创建键,才能通过
data.values.key
修改它。直接给values的新键赋值不会建立事件代理——只会创建一个不触发事件的普通属性。

Object/Array Mutation Does Not Trigger Events

对象/数组修改不会触发事件

Mutating a stored object or array in place does not emit
changedata
because the reference has not changed. You must re-set the key with a new reference to trigger the event.
原地修改存储的对象或数组不会触发
changedata
事件,因为引用没有改变。你必须用新引用重新设置该键才能触发事件。

Registry Listeners Persist Across Scene Restarts

注册表监听器会跨场景重启保留

The registry lives on the Game object. Listeners added to
this.registry.events
are NOT cleaned up when a scene restarts. Always remove them on
SHUTDOWN
:
js
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);
    });
}
注册表属于Game对象。添加到
this.registry.events
的监听器不会在场景重启时被清理。务必在
SHUTDOWN
时移除它们:
js
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);
    });
}

Frozen DataManagers Fail Silently

冻结的DataManager会静默失效

When
freeze
is
true
, all write operations (
set
,
remove
,
inc
,
toggle
,
pop
,
merge
) silently do nothing. No error is thrown and no event is emitted. This can be confusing if you forget you froze the data.
freeze
true
时,所有写入操作(
set
remove
inc
toggle
pop
merge
)都会静默失效。不会抛出错误,也不会触发事件。如果忘记已冻结数据,这可能会造成混淆。

Scene Data Plugin Shutdown vs Destroy

场景数据插件的关闭与销毁

The
DataManagerPlugin
removes its shutdown listener on shutdown but does NOT clear data on shutdown. Data persists if the scene restarts. It only fully resets on scene destroy. If you need a clean slate on restart, manually reset in a shutdown listener:
js
this.events.once('shutdown', () => {
    this.data.reset();
});
DataManagerPlugin
会在关闭时移除关闭监听器,但不会在关闭时清空数据。如果场景重启,数据会保留。只有在场景销毁时才会完全重置。如果需要重启时清空数据,请在关闭监听器中手动重置:
js
this.events.once('shutdown', () => {
    this.data.reset();
});

inc()
on Non-Numeric Values

对非数值使用
inc()

inc()
uses the
+
operator internally. On strings it concatenates rather than adds numerically. On booleans, they coerce to 0 or 1 before incrementing. Only use
inc()
on keys you know hold numbers.
inc()
内部使用
+
运算符。对字符串会进行拼接而非数值相加;对布尔值会先转换为0或1再递增。仅对已知存储数字的键使用
inc()

reset()
Emits No Events

reset()
不会触发事件

Calling
reset()
clears all data silently -- no
removedata
events fire for the deleted keys. If you need removal events for each key, iterate and call
remove()
individually instead.
调用
reset()
会静默清空所有数据——不会为删除的键触发
removedata
事件。如果需要为每个键触发移除事件,请遍历并逐个调用
remove()

Freezing Can Interrupt Batch Operations

冻结会中断批量操作

setFreeze(true)
takes effect immediately. If you freeze mid-way through a series of
set()
calls, subsequent calls in the batch silently no-op. Always freeze only after all writes are complete.
setFreeze(true)
会立即生效。如果在一系列
set()
操作中途冻结,后续操作会静默失效。请在所有写入操作完成后再冻结。

getAll()
Returns a Snapshot

getAll()
返回快照

getAll()
returns a new plain object each time. It is a shallow copy -- primitive values are independent, but object/array values still share references with the DataManager's internal storage.
getAll()
每次都会返回一个新的普通对象。它是浅拷贝——原始值独立,但对象/数组值仍与DataManager内部存储共享引用。

First Argument in changedata-key Callbacks

changedata-key回调的第一个参数

For the generic
changedata
event, the callback receives
(parent, key, value, previousValue)
. For the key-specific
changedata-{key}
event, the
key
argument is omitted:
(parent, value, previousValue)
. This difference is easy to miss.
通用
changedata
事件的回调接收
(parent, key, value, previousValue)
。而特定键
changedata-{key}
事件的回调会省略
key
参数:
(parent, value, previousValue)
。这个差异很容易被忽略。

Source File Map

源码文件映射

PathDescription
src/data/DataManager.js
Core DataManager class -- set, get, each, merge, remove, query, freeze, events
src/data/DataManagerPlugin.js
Scene plugin extending DataManager; registered as
this.data
src/data/events/index.js
Event constant exports (CHANGE_DATA, SET_DATA, REMOVE_DATA, CHANGE_DATA_KEY, DESTROY)
src/data/events/SET_DATA_EVENT.js
'setdata'
-- emitted when a new key is created
src/data/events/CHANGE_DATA_EVENT.js
'changedata'
-- emitted when an existing key's value changes
src/data/events/CHANGE_DATA_KEY_EVENT.js
'changedata-'
-- per-key change event prefix
src/data/events/REMOVE_DATA_EVENT.js
'removedata'
-- emitted when a key is removed
src/data/events/DESTROY_EVENT.js
'destroy'
-- DataManager listens for this from its parent
src/gameobjects/GameObject.js
setData, getData, incData, toggleData, setDataEnabled convenience methods
src/core/Game.js
Creates
game.registry
-- the global DataManager instance
src/scene/Scene.js
Exposes
this.registry
(injected from Game) and
this.data
(DataManagerPlugin)
路径描述
src/data/DataManager.js
核心DataManager类——set、get、each、merge、remove、query、freeze、事件
src/data/DataManagerPlugin.js
继承DataManager的场景插件;注册为
this.data
src/data/events/index.js
事件常量导出(CHANGE_DATA、SET_DATA、REMOVE_DATA、CHANGE_DATA_KEY、DESTROY)
src/data/events/SET_DATA_EVENT.js
'setdata'
——创建新键时触发
src/data/events/CHANGE_DATA_EVENT.js
'changedata'
——已有键的值变更时触发
src/data/events/CHANGE_DATA_KEY_EVENT.js
'changedata-'
——特定键变更事件前缀
src/data/events/REMOVE_DATA_EVENT.js
'removedata'
——键被移除时触发
src/data/events/DESTROY_EVENT.js
'destroy'
——DataManager监听父对象的销毁事件
src/gameobjects/GameObject.js
setData、getData、incData、toggleData、setDataEnabled便捷方法
src/core/Game.js
创建
game.registry
——全局DataManager实例
src/scene/Scene.js
暴露
this.registry
(从Game注入)和
this.data
(DataManagerPlugin)