616 文字
3 分
Phaser3 + Redux + TypeScript

Reduxを使えば異なるPhaserシーン間でスコアを共有できます。以下に具体的な実装方法を説明します。
「ランダムに画面に的(ターゲット)が出現し、それをクリックすると得点がアップする」
このようなゲームは「クリックターゲットゲーム」「モグラたたき風ゲーム」などと呼ばれます。

実装手順(Phaser3 + Redux + TypeScript)#

1. Redux Storeの設定#

src/redux/gameSlice.ts
import { createSlice } from '@reduxjs/toolkit';
interface GameState {
score: number;
}
const initialState: GameState = {
score: 0,
};
export const gameSlice = createSlice({
name: 'game',
initialState,
reducers: {
incrementScore: (state) => {
state.score += 1;
},
resetScore: (state) => {
state.score = 0;
}
}
});
export const { incrementScore, resetScore } = gameSlice.actions;
export default gameSlice.reducer;

2. Storeの統合#

src/redux/store.ts
import { configureStore } from '@reduxjs/toolkit';
import gameReducer from './gameSlice';
export const store = configureStore({
reducer: {
game: gameReducer
}
});
export type RootState = ReturnType;
export type AppDispatch = typeof store.dispatch;

3. HUDシーンの実装#

src/scenes/HudScene.ts
import Phaser from 'phaser';
import { store } from '../redux/store';
import { useAppSelector } from '../redux/hooks';
export class HudScene extends Phaser.Scene {
private scoreText!: Phaser.GameObjects.Text;
constructor() {
super({ key: 'HudScene' });
}
create() {
this.scoreText = this.add.text(10, 10, 'Score: 0', {
fontSize: '24px',
color: '#ffffff'
});
// Reduxの状態変化を監視
store.subscribe(() => {
const score = store.getState().game.score;
this.scoreText.setText(`Score: ${score}`);
});
}
}

4. ゲームシーンの修正#

src/scenes/GameScene.ts
import Phaser from 'phaser';
import { store } from '../redux/store';
import { incrementScore } from '../redux/gameSlice';
export class GameScene extends Phaser.Scene {
constructor() {
super({ key: 'GameScene' });
}
create() {
// 的を作成するロジック
const target = this.add.circle(400, 300, 20, 0xff0000)
.setInteractive()
.on('pointerdown', () => {
store.dispatch(incrementScore());
target.destroy();
});
}
}

5. シーン起動設定#

main.ts
import Phaser from 'phaser';
import { GameScene } from './scenes/GameScene';
import { HudScene } from './scenes/HudScene';
const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: 800,
height: 600,
scene: [GameScene, HudScene], // 複数シーンを同時起動
parent: 'game-container',
};

動作のポイント#

  1. 複数シーン同時実行:

    • scene: [GameScene, HudScene] で両シーンを並列実行
    • HUDシーンは常に前面に表示される
  2. Reduxの状態同期:

    • store.subscribe() で状態変化を監視
    • スコア更新時に自動でテキスト更新
  3. PhaserとReactの統合:

// Reactコンポーネント例
import { useSelector } from 'react-redux';
const GameContainer = () => {
const score = useSelector((state: RootState) => state.game.score);
return (
<div>
<div id="game-container" />
<div className="overlay-score">React側スコア: {score}</div>
</div>
);
};

最適化のヒント#

  • デバウンス処理: 頻繁な更新がある場合

    store.subscribe(() => {
    this.time.delayedCall(100, () => {
    this.scoreText.setText(`Score: ${store.getState().game.score}`);
    });
    });
  • パフォーマンス計測:

    store.ts
    import { Middleware } from '@reduxjs/toolkit';
    const phaserMiddleware: Middleware = store => next => action => {
    const start = performance.now();
    const result = next(action);
    console.log(`Action ${action.type} took ${performance.now() - start}ms`);
    return result;
    };
    export const store = configureStore({
    reducer: { /* ... */ },
    middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(phaserMiddleware)
    });

Reduxを活用することで、シーン間の状態管理がシンプルになり、ゲームの状態を一元管理できます。HUDシーン以外にも、ポーズメニューやリザルト画面など、さまざまなUI要素と連携可能です。