616 文字
3 分
Phaser3 + Redux + TypeScript
Reduxを使えば異なるPhaserシーン間でスコアを共有できます。以下に具体的な実装方法を説明します。
「ランダムに画面に的(ターゲット)が出現し、それをクリックすると得点がアップする」
このようなゲームは「クリックターゲットゲーム」「モグラたたき風ゲーム」などと呼ばれます。
実装手順(Phaser3 + Redux + TypeScript)
1. Redux Storeの設定
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の統合
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シーンの実装
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. ゲームシーンの修正
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. シーン起動設定
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',};
動作のポイント
-
複数シーン同時実行:
scene: [GameScene, HudScene]
で両シーンを並列実行- HUDシーンは常に前面に表示される
-
Reduxの状態同期:
store.subscribe()
で状態変化を監視- スコア更新時に自動でテキスト更新
-
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要素と連携可能です。