phaser
Phaser 3 のシーンベースアーキテクチャと集中管理された状態を使って、ブラウザ向け2Dゲームを構築します。新しい2Dゲームの作成、ゲーム機能の追加、Phaserを使った開発、またはスプライトベースのWebゲーム制作に取り組む際に活用してください。
description の原文を見る
> Build 2D browser games with Phaser 3 using scene-based architecture and centralized state. Use when creating a new 2D game, adding 2D game features, working with Phaser, or building sprite-based web games.
SKILL.md 本文
Phaser 3 ゲーム開発
あなたはgame-creatorプラグインを使用してゲームを構築する、エキスパートPhaserゲーム開発者です。以下のパターンに従い、よく構造化され、ビジュアルに洗練された、保守性の高い2Dブラウザゲームを作成してください。
コア原則
- コアループが最初 — ポーリッシュの前に最小限のゲームプレイループを実装します: boot → preload → create → update。ビジュアル、オーディオ、またはジュースの前に、勝利/敗北条件とスコアリングを追加してください。初期スコープを小さく保つ: 1シーン、1メカニクス、1失敗条件。スペクタクルEventBusフック (
SPECTACLE_*イベント) をコアループと同時に配線します — これらはディファードポーリッシュではなく、スキャフォルディングの一部です。 - TypeScript優先 — 型安全性とIDEサポートのため、常にTypeScriptを使用してください
- シーンベースのアーキテクチャ — 各ゲーム画面はScene; 焦点を保ちます
- Viteバンドリング — 公式の
phaserjs/template-vite-tsテンプレートを使用します - 継承よりコンポジション — 深いクラス階層よりも、動作の構成を優先してください
- データドリブン設計 — レベル、敵、設定をJSON/データファイルで定義します
- イベント駆動通信 — すべてのシーン間/システム間通信はEventBus経由です
- 再起動安全 — ゲームプレイは完全に再起動安全で決定論的である必要があります。
GameState.reset()はきれいな状態を復元する必要があります。再起動間で古い参照、残っているタイマー、またはリークされたイベントリスナーはありません。
スペクタクルイベント
すべてのプレイヤーアクションとゲームイベントは、少なくとも1つのスペクタクルイベントを発行する必要があります。これらのフックはテンプレートEventBusに存在します — デザインパスがそれらに視覚効果を付加します。
| イベント | 定数 | 発行タイミング |
|---|---|---|
spectacle:entrance | SPECTACLE_ENTRANCE | プレイヤー/エンティティが画面に最初に表示されるときに create() で発行 |
spectacle:action | SPECTACLE_ACTION | すべてのプレイヤー入力 (タップ、ジャンプ、シュート、スワイプ) 時に発行 |
spectacle:hit | SPECTACLE_HIT | プレイヤーが敵にヒット/破壊、アイテム収集、またはスコア時に発行 |
spectacle:combo | SPECTACLE_COMBO | ミスなしで連続ヒット/スコアが発生したときに発行。 { combo: n } を渡します |
spectacle:streak | SPECTACLE_STREAK | コンボがマイルストーン (5、10、25、50) に達したときに発行。 { streak: n } を渡します |
spectacle:near_miss | SPECTACLE_NEAR_MISS | プレイヤーが危険をかろうじて回避したときに発行 (衝突半径の約20%以内) |
ルール: ゲームプレイの瞬間にスペクタクルイベントがない場合は追加してください。デザインパスは、フックできないものをポーリッシュすることはできません。
必須規約
すべてのゲームはgame-creator規約に従う必要があります:
core/ディレクトリ EventBus、GameState、Constants付き- EventBusシングルトン —
domain:actionイベント命名、シーン直接参照なし - GameStateシングルトン — 集約状態とクリーン再起動用の
reset() - Constants файл — すべてのマジックナンバー、色、速度、設定値 — ゼロハードコード値
- シーンクリーンアップ —
shutdown()でEventBusリスナーを削除
詳細なコード例についてはconventions.mdを参照してください。
プロジェクトセットアップ
公式Vite + TypeScriptテンプレートを出発点として使用します:
npx degit phaserjs/template-vite-ts my-game
cd my-game && npm install
必須ディレクトリ構造
src/
├── core/
│ ├── EventBus.ts # シングルトンイベントバス + イベント定数
│ ├── GameState.ts # reset() 付きの集約状態
│ └── Constants.ts # すべての設定値
├── scenes/
│ ├── Boot.ts # 最小限のセットアップ、Game シーン開始
│ ├── Preloader.ts # すべてのアセットをロード、プログレスバーを表示
│ ├── Game.ts # メインゲームプレイ (すぐに開始、タイトル画面なし)
│ └── GameOver.ts # エンドスクリーン (再起動機能付き)
├── objects/ # ゲームエンティティ (Player、Enemy など)
├── systems/ # マネージャーとサブシステム
├── ui/ # UIコンポーネント (ボタン、バー、ダイアログ)
├── audio/ # オーディオマネージャー、音楽、SFX
├── config.ts # Phaser.Types.Core.GameConfig
└── main.ts # エントリーポイント
詳細な設定とツーリングについてはproject-setup.mdを参照してください。
シーンアーキテクチャ
- ライフサイクル:
init()→preload()→create()→update(time, delta) - シーン遷移からデータを受け取るために
init()を使用 - 専用の
Preloaderシーンでアセットをロード、すべてのシーンではなく update()を軽く保つ — サブシステムとゲームオブジェクトに委譲- デフォルトではタイトル画面なし — ゲームプレイに直接起動します。ユーザーが明示的に要求した場合のみ、タイトル/メニューシーンを追加します
- ゲーム内スコアHUDなし — Play.funウィジェットはゲームの上部デッドゾーンにスコアを表示します。スコア表示用に別のUISceneまたはHUDオーバーレイを作成しないでください
- UIオーバーレイ (ポーズメニュー) には、要求された場合のみ並列シーンを使用
Play.fun安全ゾーン
ゲームがモバイルSafariのPlay.funダッシュボード内で実行される場合、SDKはゲームiframeの document.documentElement に対してCSSカスタムプロパティを設定します:
--ogp-safe-top-inset— Play.funヘッダーバブルの下のスペース (モバイルで約68px)--ogp-safe-bottom-inset— Safariボトムコントロールの上のスペース (モバイルで約148px)
ダッシュボード外で実行している場合 (デスクトップ、スタンドアロン) の両方デフォルトは 0px です。
テンプレートの Constants.js はこれらを起動時に読み込み、キャンバスピクセル (CSS値×DPR) で SAFE_ZONE.TOP と SAFE_ZONE.BOTTOM を公開します。静的フォールバック (GAME.HEIGHT * 0.08) は、SDKなしでもトップ安全ゾーンが機能するようにします。
ルール:
- すべてのUIテキスト、ボタン、HUD要素は
SAFE_ZONE.TOP下およびGAME.HEIGHT - SAFE_ZONE.BOTTOM上に配置する必要があります - ゲームプレイエンティティは安全ゾーン領域に生成されてはいけません
- ゲームオーバー画面、スコアパネル、再起動ボタンは
SAFE_ZONE.TOPとSAFE_ZONE.BOTTOMの両方からオフセットする必要があります - UI シーンの比例位置を計算するために
const usableH = GAME.HEIGHT - SAFE_ZONE.TOP - SAFE_ZONE.BOTTOMを使用してください - ゲームキャンバスと背景は完全なビューポートを埋める (ブラウザクロムの後ろに出血)
- ボトムのタッチコントロールは
SAFE_ZONE.BOTTOMを考慮する必要があります
import { SAFE_ZONE } from '../core/Constants.js';
// 任意のUIシーン内:
const safeTop = SAFE_ZONE.TOP;
const safeBottom = SAFE_ZONE.BOTTOM;
const usableH = GAME.HEIGHT - safeTop - safeBottom;
const title = this.add.text(cx, safeTop + usableH * 0.15, 'GAME OVER', { ... });
const button = createButton(scene, cx, safeTop + usableH * 0.6, 'PLAY AGAIN', callback);
// タッチコントロール / ボトムHUD:
const bottomY = GAME.HEIGHT - safeBottom - 40 * PX;
Constants.jsでの動作方法:
function _readSafeInsets() {
const s = getComputedStyle(document.documentElement);
const top = parseInt(s.getPropertyValue('--ogp-safe-top-inset')) || 0;
const bottom = parseInt(s.getPropertyValue('--ogp-safe-bottom-inset')) || 0;
return { top: top * DPR, bottom: bottom * DPR };
}
const _insets = _readSafeInsets();
export const SAFE_ZONE = {
TOP: Math.max(GAME.HEIGHT * 0.08, _insets.top),
BOTTOM: _insets.bottom,
LEFT: 0,
RIGHT: 0,
};
- EventBus経由でシーン間通信 (直接参照なし)
パターンと例についてはscenes-and-lifecycle.mdを参照してください。
ゲームオブジェクト
- カスタムオブジェクトのために
Phaser.GameObjects.Sprite(または他の基本クラス) を拡張 - オブジェクトプーリング (弾、コイン、敵) には
Phaser.GameObjects.Groupを使用 - 複合オブジェクトには
Phaser.GameObjects.Containerを使用、ただしネストは深くしないでください - カスタムオブジェクトを
GameObjectFactoryに登録してシーンレベルアクセスのため
実装パターンについてはgame-objects.mdを参照してください。
物理エンジン
- Arcade Physics — シンプルなゲーム (プラットフォーマー、トップダウン) に使用。高速で軽量です。
- Matter.js — リアルな衝突、制約、または複雑な形状が必要な場合に使用します。
- 同じゲームで物理エンジンを混ぜないでください。
- キャラクター移動 (アイドル、歩行、ジャンプ、攻撃) にはステートパターンを使用します。
詳細についてはphysics-and-movement.mdを参照してください。
パフォーマンス (重要ルール)
- テクスチャアトラスを使用 — スプライトをアトラスにパック、大規模な個別画像をロードしないでください
- オブジェクトプーリング —
maxSize付きグループを使用;setActive(false)/setVisible(false)でリサイクル - 更新作業を最小化 — アクティブなオブジェクトのみイテレート;
getChildren().filter(c => c.active)を使用 - カメラカリング — 大きな世界に対して有効; オフスクリーン オブジェクトはレンダリングをスキップ
- バッチレンダリング — 1フレームあたりのユニークなテクスチャが少ない = より良い描画呼び出しバッチング
- モバイル — パーティクルカウントを削減、物理を単純化、30fpsターゲットを検討
pixelArt: true— ゲーム設定でピクセルアートゲーム用に有効 (最近傍スケーリング)
完全な最適化ガイドについてはassets-and-performance.mdを参照してください。
高度なパターン
- bitECS付きECS — Entity Component System データ指向設計用 (Phaser 4で内部的に使用)
- ステートマシン — エンティティ動作状態をクリーンに管理
- シングルトンマネージャー — クロスシーンサービス (オーディオ、セーブデータ、アナリティクス)
- イベントバス — 共有EventEmitterでシステムを分離
- Tiled統合 — レベルデザインにTiled mapエディターを使用
実装についてはpatterns.mdを参照してください。
モバイル入力戦略 (60/40ルール)
すべてのゲームは、明示的に別途指定されない限り、デスクトップとモバイルの両方で機能する必要があります。トレードオフのために60%モバイル / 40%デスクトップにフォーカスします。各ゲームコンセプトに最適なモバイル入力を選択:
| ゲームタイプ | プライマリモバイル入力 | デスクトップ入力 |
|---|---|---|
| プラットフォーマー | 左/右半分をタップ + タップでジャンプ | 矢印キー / WASD |
| ランナー/エンドレス | タップ / スワイプアップでジャンプ | スペース / 上矢印 |
| パズル/マッチ | ターゲットをタップ (44pxミニ) | クリック |
| シューター | 仮想ジョイスティック + タップで発火 | マウス + WASD |
| トップダウン | 仮想ジョイスティック | 矢印キー / WASD |
実装パターン
入力をゲーム不可知な inputState オブジェクトに抽象化:
// シーン update() 内:
const isMobile = this.sys.game.device.os.android ||
this.sys.game.device.os.iOS || this.sys.game.device.os.iPad;
let left = false, right = false, jump = false;
// キーボード
left = this.cursors.left.isDown || this.wasd.left.isDown;
right = this.cursors.right.isDown || this.wasd.right.isDown;
jump = Phaser.Input.Keyboard.JustDown(this.spaceKey);
// タッチ (キーボードとマージ)
if (isMobile) {
// 左半分のタップ = 左、右 = 右、またはタップゾーンを使用
this.input.on('pointerdown', (p) => {
if (p.x < this.scale.width / 2) left = true;
else right = true;
});
}
this.player.update({ left, right, jump });
レスポンシブキャンバス設定 (Retina/高DPI)
完全なレスポンシブキャンバス設定、エンティティサイジング、HTMLボイラープレート、ポートレートファーストゲームパターンについてはproject-setup.mdを参照してください。
可視タッチコントロール
タッチ対応デバイスで常に視覚的なタッチインジケーターを表示 — 見えないタップゾーンに依存しないでください。機能検出 (OS ベースの検出ではなく) を使用してタッチサポートを判断:
// 良い — タッチラップトップ、タブレット、2-in-1を検出
const hasTouch = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0);
// 悪い — タッチスクリーンラップトップを逃す、iPadOS (デスクトップとして報告)
const isMobile = device.os.android || device.os.iOS;
画面下部に半透明の矢印ボタン (または方向インジケーター) をレンダリング。Constants.jsの TOUCH 定数をサイジング (キャンバス幅の12%)、アルファ (アイドル0.35 / アクティブ0.6)、マージンに使用。入力状態に基づいて update() ループ内のアルファを更新して視覚的フィードバックを提供します。
すべてのデバイスでポインター入力 (pointerdown、pointermove、pointerup) を有効にする — ポインターイベントはマウスとタッチの両方で機能します。これにより、個別のモバイル/デスクトップ入力コードパスが不要になります。
モバイルの最小エンティティサイズ
収集品、ハザード、インタラクティブアイテムは、携帯画面での認識性のために少なくとも GAME.WIDTH の7~8% である必要があります。より小さいエンティティはモバイルで識別不可能なブロブになります。
// 良い — モバイルで認識可能
ATTACK_WIDTH: _canvasW * 0.09,
POWERUP_WIDTH: _canvasW * 0.072,
// 悪い — 携帯画面で小さすぎます
ATTACK_WIDTH: _canvasW * 0.04,
POWERUP_WIDTH: _canvasW * 0.035,
メインプレイヤーキャラクターの場合、GAME.WIDTH の12~15%を使用します (上記のEntity Sizingを参照)。
ボタンパターン (Container + Graphics + Text)
完全なボタン実装パターン (Container + Graphics + Text とホバー/プレス状態) と回避すべき壊れたパターンのリストについてはgame-objects.mdを参照してください。
アンチパターン (これらは避けてください)
- ブロート
update()メソッド — すべてのゲームロジックを1つの巨大な更新とネストされた条件付きに入れないでください。オブジェクトとシステムに委譲します。 - シーン注入マッププロパティの上書き —
world、input、cameras、add、make、scene、sys、game、cache、registry、sound、textures、events、physics、matter、time、tweens、lights、data、load、anims、renderer、pluginsという名前のプロパティを決して名付けないでください。これらはPhaserによって予約されています。 update()内でのオブジェクト作成 (プーリングなし) — これはGCスパイクを引き起こします。頻繁に作成/破壊されるオブジェクトは常にプール。高価なフレームごとの割り当てを避ける — オブジェクト、配列、一時変数を再利用します。- 個別スプライトの代わりにアトラスをロード — 個別のテクスチャは各描画呼び出しです。パックします。
- シーンを緊密にカップリング — シーン間で直接参照を保存しないでください。EventBusを使用してください。
deltaを update で無視 — 常にフレーム数ではなく、deltaを時間ベースの移動に使用してください。- 深いコンテナネスト — コンテナーは子のレンダーバッチングを無効にします。階層をフラットに保ちます。
- クリーンアップしない —
shutdown()でイベントリスナーとタイマーを削除してメモリリークを防ぎます。これは再起動安全性に重要です — 古いリスナーは再起動後のダブルファイアリングとゴーストブハビアを引き起こします。 - ハードコード値 — すべての数値は
Constants.tsに属します。ゲームロジック内にマジックナンバーはありません。 - 配線されていない物理衝突体 —
physics.add.existing(obj, true)で静的ボディを作成することは、それ自体は何もしません。2つのボディを接続するためにphysics.add.collider(bodyA, bodyB, callback)を呼び出す必須です。すべての静的衝突体 (地面、壁、プラットフォーム) は、相互作用するエンティティに配線する明示的な衝突体またはオーバーラップ呼び出しが必要です。 - 見えないまたは非表示のボタン要素 — インタラクティブなゲームオブジェクトに
setAlpha(0)を設定して、Graphicsまたは他の表示オブジェクトを上に重ねないでください。ボタンについては、常にContainer + Graphics + Textパターンを使用します (参照game-objects.md)。一般的な壊れたパターン: (1) テキスト追加後にGraphicsレクトを描画、ラベルを後ろに隠す。 (2) Zoneをヒット領域として作成しGraphicsを描画、Zoneに到達不可能にする。 (3) Textをインタラクティブにするが、その後描画されたGraphics背景で覆う。修正は常に: Container最初、Graphicsをコンテナーに追加、テキストをコンテナーに追加 (その順序)、Containerはインタラクティブな要素です。 - ミュートトグルなし —
mute-buttonルールを参照。オーディオ付きゲームはミュートトグルが必要です。
例
シンプルゲーム— 最小限の完全なPhaserゲーム (コレクターゲーム)複雑なゲーム— ステートマシン、プーリング、EventBus、すべての規約を備えたマルチシーンゲーム
出荷前検証チェックリスト
ゲームが完全だと見なす前に検証:
- コアループが機能 — プレイヤーは開始、プレイ、負け/勝ち、結果表示ができます
- 再起動がクリーンに機能 —
GameState.reset()はクリーンな状態を復元、古いリスナーまたはタイマーはありません - タッチ + キーボード入力 — ゲームはモバイル (タップ/スワイプ) とデスクトップ (キーボード/マウス) で機能
- レスポンシブキャンバス —
Scale.FIT+CENTER_BOTH+zoom: 1/DPR(DPR乗算なし次元) Retina で鮮明 - すべての値がConstantsにある — ゲームロジック内のゼロハードコードマジックナンバー
- EventBusのみ — クロスシーン/モジュール通信のための直接インポートなし
- シーンクリーンアップ — すべてのEventBusリスナーは
shutdown()で削除 - 物理配線 — すべての静的ボディは明示的な
collider()またはoverlap()呼び出しを持つ - オブジェクトプーリング — 頻繁に作成/破壊されるオブジェクトは
maxSize付きグループを使用 - デルタベースの移動 — すべてのモーション
deltaを使用、フレームカウントではなく - ミュートトグル —
mute-buttonルールを参照 - スペクタクルフックが配線 — すべてのプレイヤーアクションとゲームイベント
SPECTACLE_*イベントを発行; エントランスシーケンスcreate()で発火 - ビルドパス —
npm run buildはエラーなしで成功 - コンソールエラーなし — ゲームは未処理の例外またはWebGL障害なしで実行
リファレンスファイル
| ファイル | トピック |
|---|---|
conventions.md | 必須game-creatorアーキテクチャ規約 |
project-setup.md | スキャフォルディング、Vite、TypeScript設定、レスポンシブキャンバス、エンティティサイジング、ポートレートモード |
scenes-and-lifecycle.md | シーンシステムディープダイブ |
game-objects.md | カスタムオブジェクト、グループ、コンテナー、ボタンパターン |
physics-and-movement.md | 物理エンジン、移動パターン |
assets-and-performance.md | アセット、最適化、モバイル |
patterns.md | ECS、ステートマシン、シングルトン |
no-asset-design.md | 手続き型ビジュアル: グラデーション、パララックス、パーティクル、ジュース |
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- opusgamelabs
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/opusgamelabs/game-creator / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。