Writing Phaser 3 Games について
実践的な実装パターンを必要とする開発者向けの Phaser 3 ゲーム開発スキルです。18 のトピック別ファイルで、シーン、物理演算、入力、アニメーション、性能などをコード例や注意点とともに扱います。
主な機能
- 0118 のトピック別パターンガイド
- 02シーン構成とトランジション
- 03物理演算、衝突、移動のパターン
- 04入力、アニメーション、状態管理
- 05オブジェクトプールと性能改善
- 06コード構成とよくある問題
活用シーン
- 01複数シーンの Phaser ゲームを構成する
- 02キーボード、ポインター、タッチ入力を実装する
- 03グリッドベースのゲームロジックを構築する
- 04性能やメモリの問題を調べる
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ tomcoolpxl/ sugar-splat --skill writing-phaser-3-gamesインストール後、Claude Code で/writing-phaser-3-gamesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
knowledgebase/01-scene-architecture.md05-animation-system.md03-physics-collision.md02-asset-management.md08-object-pooling-memory.md09-grid-systems.md06-input-handling.md04-movement-patterns.md10-custom-game-objects.md07-state-management.md13-audio-integration.md12-tween-visual-effects.md15-algorithm-implementations.md11-ui-hud-patterns.md16-performance-optimization.mdTOC.md14-game-loop-patterns.md17-code-organization.md18-development-philosophy.md詳細
Phaser 3 ゲーム開発スキル
クイックスタート
よく使われるパターン
複数シーンのフロー
const config = {
scene: [ Boot, Preloader, MainMenu, Game, GameOver ]
};
// Boot → Preloader → MainMenu → Game → GameOver
オブジェクトプーリング
create() {
this.projectiles = this.physics.add.group({
classType: Projectile,
frameQuantity: 20,
active: false,
visible: false
});
}
fire() {
const projectile = this.projectiles.getFirstDead(false);
if (projectile) projectile.fire(x, y);
}
グローバルアニメーション
// In Preloader.js create()
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
JustDown 入力
if (Phaser.Input.Keyboard.JustDown(this.spacebar)) {
this.jump();
}
ナビゲーションガイド
このスキルの使い方
このスキルでは、Phaser 3 開発のあらゆる側面を網羅する、18 個の包括的なパターンファイルを利用できます。各ファイルには、詳細なパターン、コード例、ベストプラクティスが含まれています。
特定のパターンを見つけるには:
# Read a specific topic
Read knowledgebase/06-input-handling.md
# Search for a pattern across all files
grep -r "object pooling" knowledgebase/
# Find patterns by keyword
grep -i "animation" knowledgebase/*.md
grep -i "collision" knowledgebase/*.md
番号からすばやく検索:
- 01 = シーンアーキテクチャ
- 02 = アセット管理
- 03 = 物理演算と衝突
- 04 = 移動パターン
- 05 = アニメーションシステム
- 06 = 入力処理
- 07 = 状態管理
- 08 = オブジェクトプーリングとメモリ
- 09 = グリッドシステム
- 10 = カスタムゲームオブジェクト
- 11 = UI/HUD パターン
- 12 = Tween と視覚効果
- 13 = オーディオ統合
- 14 = ゲームループパターン
- 15 = アルゴリズムの実装
- 16 = パフォーマンス最適化
- 17 = コード構成
- 18 = 開発理念
目次
1. シーンアーキテクチャ
knowledgebase/01-scene-architecture.md
複数シーンのフロー、UI オーバーレイ用の並列シーン、エフェクトを使ったシーン遷移、シーン間のデータ受け渡し。
主なパターン:
- Boot → Preloader → MainMenu → Game → GameOver のフロー
scene.launch()を使った並列 UI シーン- カメラのフェード遷移
init(data)によるシーンデータの受け渡し
2. アセット管理
knowledgebase/02-asset-management.md
2 段階の読み込み、テクスチャアトラス、複数形式のオーディオ、フォントの同期。
主なパターン:
- Boot でブートストラップアセットを、Preloader で全アセットを読み込む
- 複数のスプライトにテクスチャアトラスを使う
- ブラウザーとの互換性を確保するための複数形式のオーディオ
- WebFont の読み込み同期
3. 物理演算と衝突
knowledgebase/03-physics-collision.md
物理演算の設定、衝突と重なりの違い、動的な反応、状態に応じた衝突処理。
主なパターン:
- 物理的なブロックには Collider、トリガーには overlap を使う
- 位置に基づく動的な反応(パドルへの衝突)
- 状態に応じた衝突チェック
- トラック/レイヤーごとの衝突分離
4. 移動パターン
knowledgebase/04-movement-patterns.md
速度ベース、時間ベースの離散移動、タイマーベース、追跡、方向の検証、画面端での折り返し。
主なパターン:
- 連続的に動くアクションゲームには速度ベースを使う
- グリッドゲームには時間ベースの離散移動を使う
- ターン制ゲームにはタイマーベースを使う
- 方向を検証して 180° の方向転換を防ぐ
5. アニメーションシステム
knowledgebase/05-animation-system.md
グローバルアニメーションの作成、逆再生アニメーション、アニメーション主導のロジック、状態に応じた制御。
主なパターン:
- Preloader でアニメーションを一度だけ作成し、どこからでも使う
- ゲームプレイとの同期にアニメーションイベントを使う
- キャッシュを使った状態ベースのアニメーション制御
- 外部アニメーション JSON データ
6. 入力処理
knowledgebase/06-input-handling.md
キーボード、ポインター、タッチ、JustDown パターン、2 種類の入力方式への対応、入力制御、クリーンアップ。
主なパターン:
- 1 回の押下を検出する JustDown
- キーボードとポインターの両方に対応
- アニメーション中の入力制御
- イベント駆動型のポインター移動
once()による 1 回限りの入力処理
7. 状態管理
knowledgebase/07-state-management.md
シーンレベルの状態、永続化のためのレジストリ、localStorage、GameObject のデータコンポーネント、ステートマシン。
主なパターン:
- 設定にはコンストラクター、リセット可能な状態には init() を使う
- シーン間のデータ共有にレジストリを使う
- カスタムプロパティには GameObject のデータコンポーネントを使う
- ブール値フラグとステートマシンの使い分け
8. オブジェクトプーリングとメモリ
knowledgebase/08-object-pooling-memory.md
グループベースのプーリング、有効化/無効化のパターン、オブジェクトの再利用、動的テクスチャのクリーンアップ。
主なパターン:
frameQuantityを使って事前に作成し、getFirstDead()で再利用する- 作成/破棄の代わりに有効化/無効化する
- 再利用可能なオブジェクトのリセットパターン
- 動的テクスチャのクリーンアップを防止する
9. グリッドシステム
knowledgebase/09-grid-systems.md
座標の使い分け、2D 配列、隣接判定ヘルパー、グリッドへの整列、可視化。
主なパターン:
- グリッド座標とピクセル座標を分離する
- 境界チェック付きの2D配列
- 隣接判定ヘルパー(8方向、4方向)
- グリッドに整列したグループの作成
10. カスタムゲームオブジェクト
knowledgebase/10-custom-game-objects.md
Sprite/Image の拡張、コンポジションパターン、グループの拡張、自己登録。
主なパターン:
- 物理演算とアニメーションが必要な場合は Sprite を拡張する
- 物理演算を使う静的スプライトには Image を拡張する
- 視覚要素を持たないマネージャーにはコンポジションを使う
- アニメーションには
super.preUpdate()の呼び出しが必要
11. UI/HUD のパターン
knowledgebase/11-ui-hud-patterns.md
テキストのスタイル設定、位置指定、動的更新、ビットマップフォント、アイコンカウンター、レイヤー化。
主なパターン:
- 位置指定にはテキストの原点を使う(左上、中央など)
- トゥイーンを使ったアニメーション付きカウンター
- アイコンベースのカウンター(ハート、残機)
- UI のレイヤー化に深度/Z順序を使う
12. トゥイーンと視覚効果
knowledgebase/12-tween-visual-effects.md
基本的なトゥイーン、段階的なアニメーション、演出シーケンス、カメラ効果、パーティクル。
主なパターン:
- トゥイーンのコールバックを使ったシーケンス制御
- グリッドの段階的なアニメーション
- 遅延を積み重ねた演出シーケンス
- カメラのシェイク、フラッシュ、フェード
- パーティクルエミッター
13. オーディオの統合
knowledgebase/13-audio-integration.md
サウンド管理、オーディオロックへの対処、オーディオの一元管理、遅延/シーケンス再生。
主なパターン:
- 複数形式のオーディオ読み込み
- オーディオロックの検出と対処
- UI シーンでのオーディオの一元管理
- シーンをまたいだ音楽の再生
14. ゲームループのパターン
knowledgebase/14-game-loop-patterns.md
標準的な更新処理、最小限のイベント駆動型処理、カスタムオブジェクトの preUpdate、処理の委譲、タイマー。
主なパターン:
- update() 内で早期終了ガードを使う
- ターン制ゲームではイベント駆動型にする
- タイマーによる繰り返しイベント/単発イベント
- マネージャーへの更新処理の委譲
15. アルゴリズムの実装
knowledgebase/15-algorithm-implementations.md
フラッドフィル、賢いランダム配置、解けるパズルの生成、近接距離の計算、追従チェーン、AI。
主なパターン:
- 4方向に広がる再帰的なフラッドフィル
- 配置を確実にする有効な位置の収集
- 解けるパズルを生成するウォーカーアルゴリズム
- ShiftPosition を使った追従チェーン
16. パフォーマンスの最適化
knowledgebase/16-performance-optimization.md
オブジェクトプーリング、テクスチャキャッシュ、更新処理の最小化、イベント駆動型処理、静的グループ。
主なパターン:
- オブジェクトプーリングで GC の一時停止をなくす
- 動かないオブジェクトには静的グループを使う
- update() でのポーリングよりイベント駆動型処理を使う
- レンダリング性能向上のためにテクスチャアトラスを使う
17. コードの構成
knowledgebase/17-code-organization.md
ファイル構成、ES6 モジュール、定数の管理、関心事の分離。
主なパターン:
- scenes、gameobjects、managers、utils、constants の各フォルダー
- ES6 モジュールのインポート
- スプライト/アニメーション/オーディオのキーをまとめた定数ファイル
- create() 内で初期化順序を明確にする
18. 開発哲学
knowledgebase/18-development-philosophy.md
アーキテクチャの原則、物理演算を使うタイミング、シーンの判断、更新とイベント、段階的な難易度設定。
主なパターン:
- 物理演算と手動ロジックを使い分けるタイミング
- シーンを単一、複数、並列にする場合
- Update() とイベント駆動型のアプローチ
- 段階的な難易度設定のパターン
コアパターンのリファレンス
シーンのセットアップ
export default class Game extends Phaser.Scene {
constructor() {
super('Game');
// Configuration constants
this.GRID_SIZE = 32;
}
init() {
// Reset resettable state
this.score = 0;
this.gameOver = false;
}
create() {
// Initialize objects
this.player = new Player(this);
this.enemies = this.physics.add.group();
// Setup collisions
this.physics.add.collider(this.player, this.enemies, this.onHit, null, this);
}
update(time, delta) {
if (this.gameOver) return;
// Game logic
}
}
カスタムゲームオブジェクト
export default class Player extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y) {
super(scene, x, y, 'player');
// Self-register
scene.add.existing(this);
scene.physics.add.existing(this);
// Configuration
this.setCollideWorldBounds(true);
this.isAlive = true;
}
preUpdate(time, delta) {
super.preUpdate(time, delta); // ESSENTIAL for animations
if (!this.isAlive) return;
this.handleMovement();
}
}
グリッドシステム
// Dual coordinate system
this.gridX = 5;
this.gridY = 3;
this.sprite.x = this.gridX * TILE_SIZE;
this.sprite.y = this.gridY * TILE_SIZE;
// 2D array with bounds checking
getCellXY(x, y) {
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
return null;
}
return this.grid[y][x];
}
衝突処理
// Physical collision
this.physics.add.collider(player, platforms);
// Trigger-based overlap
this.physics.add.overlap(player, coins, this.collectCoin, null, this);
// Collision with state gates
onHit(player, enemy) {
if (!player.isAlive) return;
if (player.invincible) return;
if (enemy.alpha < 1) return;
this.handleDamage(player, enemy);
}
入力パターン
create() {
// Cursor keys
this.cursors = this.input.keyboard.createCursorKeys();
// Specific key
this.spacebar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
// Pointer/touch
this.input.on('pointerdown', this.handleClick, this);
}
update() {
// Continuous input
if (this.cursors.left.isDown) {
this.player.setVelocityX(-160);
}
// Single-press input
if (Phaser.Input.Keyboard.JustDown(this.spacebar)) {
this.jump();
}
}
アニメーションのセットアップ
// In Preloader create() - global animations
this.anims.create({
key: 'player-walk',
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
// In Game create() - use animations
this.player.play('player-walk');
// Animation events
this.player.on('animationcomplete-attack', this.spawnProjectile, this);
状態管理
// Scene-level state
init() {
this.score = 0;
this.lives = 3;
this.gameOver = false;
}
// Registry for cross-scene data
this.registry.set('highscore', this.score);
const highscore = this.registry.get('highscore');
// GameObject data
sprite.setData({ gridX: 5, gridY: 3, type: 'enemy' });
const gridX = sprite.data.values.gridX;
よくある落とし穴
避けるべき重大なミス:
-
カスタムスプライトで
super.preUpdate(time, delta)を呼び忘れる- これを呼ばないとアニメーションが動作しません
- preUpdate() の最初に必ず呼び出してください
-
静的グループをスケーリングした後に
refreshBody()を呼び出さないthis.platforms.create(x, y, 'platform') .setScale(2) .refreshBody(); // REQUIRED -
オブジェクトプールを使わず、update() 内でオブジェクトを作成する
- GC の一時停止を引き起こし、パフォーマンスが低下します
- プールを事前に作成し、有効化/無効化して再利用してください
-
グリッドへのアクセス時に境界チェックを行わない
if (x < 0 || x >= width || y < 0 || y >= height) return null; -
リスナーやタイマーをクリーンアップしない
shutdown() { this.input.off('pointerdown', this.handleClick); if (this.timer) this.timer.remove(); } -
誤った衝突処理メソッドを使う
- 物理的なブロックには
colliderを使用します - トリガーやアイテム取得には
overlapを使用します
- 物理的なブロックには
-
イベントで対応できる場面で update() 内のポーリングを使う
- 距離チェックの代わりに、物理演算の overlap を使用します
- 毎フレーム確認する代わりに、ポインターイベントを使用します
-
定数を使わず値をハードコードする
// Bad: magic numbers sprite.x = 400; // Good: named constants const GRID_SIZE = 32; sprite.x = gridX * GRID_SIZE; -
init() で状態をリセットしない
- シーンを正しく再起動できません
- リセット可能な状態はコンストラクターではなく init() に設定してください
-
コールバックのコンテキストバインディングを無視する
// アロー関数または bind を使用します this.time.delayedCall(1000, () => this.start(), [], this);
パフォーマンスのヒント
- 頻繁に作成・破棄するオブジェクトには、オブジェクトプールを使用します
- テクスチャアトラスを使うと、スプライトを1枚の画像にまとめられます
- 動かないプラットフォームや壁には、静的グループを使用します
- update() 内のポーリングより、イベント駆動型のアプローチを使用します
- 更新ロジックを最小限にし、各フレームで必要な処理だけを行います
- 検索結果をキャッシュし、毎フレーム配列を検索しないようにします
- 深度は一度だけ設定し、毎フレームソートしないようにします
詳細ファイルを読むタイミング
新しいゲームを始めますか? → 01-scene-architecture.md を読んでください
パフォーマンスに問題がありますか? → 16-performance-optimization.md を読んでください
グリッドベースのゲームですか? → 09-grid-systems.md を読んでください
複雑なアニメーションですか? → 05-animation-system.md と 12-tween-visual-effects.md を読んでください
入力に問題がありますか? → 06-input-handling.md を読んでください
メモリーリークがありますか? → 08-object-pooling-memory.md を読んでください
アルゴリズムを実装しますか? → 15-algorithm-implementations.md を読んでください
アーキテクチャを決めますか? → 18-development-philosophy.md を読んでください
クイックリファレンス
シーンの流れ
Boot → Preloader → MainMenu → Game → GameOver
this.scene.start('NextScene', { score: this.score });
this.scene.launch('GameUI'); // Parallel scene
物理演算
this.physics.add.collider(a, b); // Physical blocking
this.physics.add.overlap(a, b, callback); // Trigger only
sprite.setCollideWorldBounds(true);
sprite.setImmovable(true);
グループとプーリング
this.items = this.physics.add.group({ frameQuantity: 20 });
const item = this.items.getFirstDead(false);
item.enableBody(true, x, y, true, true);
item.disableBody(true, true);
入力
this.cursors = this.input.keyboard.createCursorKeys();
Phaser.Input.Keyboard.JustDown(key)
this.input.on('pointerdown', callback, this);
トゥイーン
this.tweens.add({
targets: sprite,
x: 400,
duration: 1000,
ease: 'Power2',
onComplete: () => {}
});
カメラ
this.cameras.main.shake(duration, intensity);
this.cameras.main.fadeOut(duration);
this.cameras.main.flash(duration, r, g, b);
このスキルでは、Phaser 3 のパターンを包括的に紹介します。詳細な例や高度なテクニックについては、ナレッジベースの各ファイルをお読みください。