Claude
Skills
Sign in
Back

data-manager

Included with Lifetime
$97 forever

Use this skill when using the Phaser 4 DataManager to store custom key-value data on game objects, listen for data change events, or manage game state. Triggers on: setData, getData, data events, custom data storage.

General

What this skill does


# 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

## 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
```

## Core Concepts

### 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.
```

### Scene Data Plugin (`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.

### 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.

### Per-GameObject Data

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();
    }
});
```

## 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
```

### 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);
});
```

### 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);
```

### 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
```

### 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);
```

### 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 }
```

### 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(
Files: 1
Size: 16.5 KB
Complexity: 20/100
Category: General

Related in General