👽

Phaser3で状態管理を実装する

に公開

Phaser 3で状態管理を実装するには、アプリケーションの複雑さや要件に応じて、いくつかの方法があります。以下に一般的なアプローチを説明します。


基本的な状態管理の手法

1. グローバル変数を利用

  • シンプルな状態管理の方法として、ゲーム全体で共有するグローバル変数を利用することができます。
  • Phaser 3では、this.registry が状態の保存に使用できます。
    • this.registry はシーンからアクセス可能で、ゲーム全体で共有されます。

サンプルコード

class MainScene extends Phaser.Scene {
  constructor() {
    super({ key: 'MainScene' });
  }

  preload() {}

  create() {
    // 状態の初期化
    this.registry.set('score', 0);
    this.registry.set('playerHealth', 100);

    // 状態の更新
    this.registry.set('score', this.registry.get('score') + 10);
    console.log('Current Score:', this.registry.get('score'));

    // シーン間で状態を引き継ぐ例
    this.scene.start('NextScene');
  }
}

2. イベントエミッターを活用

  • 状態の変更や通知を管理するために、PhaserのPhaser.Events.EventEmitterを利用できます。
  • 複数のシーン間で状態変更を通知する場合に便利です。

サンプルコード

class GameState extends Phaser.Events.EventEmitter {
  constructor() {
    super();
    this.state = {
      score: 0,
      playerHealth: 100,
    };
  }

  set(key, value) {
    this.state[key] = value;
    this.emit('stateChanged', this.state);
  }

  get(key) {
    return this.state[key];
  }
}

const gameState = new GameState();

class MainScene extends Phaser.Scene {
  constructor() {
    super({ key: 'MainScene' });
  }

  create() {
    gameState.on('stateChanged', (newState) => {
      console.log('State Updated:', newState);
    });

    // 状態の更新
    gameState.set('score', 10);
  }
}

3. 外部状態管理ライブラリを導入

  • 状態管理が複雑になる場合、ReduxMobX などの外部ライブラリを利用するのも選択肢です。
  • Phaser 3と組み合わせて使う場合、ライブラリの管理部分をゲームロジックやUIに統合します。

サンプルコード(Reduxを利用)

import { createStore } from 'redux';

// 状態の初期値
const initialState = {
  score: 0,
  playerHealth: 100,
};

// Reducer関数
function gameReducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT_SCORE':
      return { ...state, score: state.score + action.payload };
    case 'DECREMENT_HEALTH':
      return { ...state, playerHealth: state.playerHealth - action.payload };
    default:
      return state;
  }
}

// Reduxストアの作成
const store = createStore(gameReducer);

class MainScene extends Phaser.Scene {
  constructor() {
    super({ key: 'MainScene' });
  }

  create() {
    // ストアの変更を監視
    store.subscribe(() => {
      console.log('State Updated:', store.getState());
    });

    // ストアの状態を更新
    store.dispatch({ type: 'INCREMENT_SCORE', payload: 10 });
  }
}

どの方法を選ぶべきか?

  1. 簡単なゲームthis.registry の使用が最適
  2. 中規模のゲームPhaser.Events.EventEmitter を導入
  3. 大規模で複雑なゲーム → ReduxやMobXといった外部ライブラリの利用を検討

Phaser 3のシンプルさを活かしたい場合は、registryEventEmitter の利用が多くのケースで十分です。また、必要に応じて外部ライブラリを組み合わせることで、拡張性を持たせることもできます。

Discussion