phaser-arcade-physics について
Phaser 4.2のゲームにArcade Physicsを導入するためのスキルです。移動、重力、衝突に加え、動的・静的ボディやグループの扱いを説明します。
主な機能
- 01Arcade Physicsワールドの設定
- 02動的・静的ボディの作成
- 03速度・加速度・反発の制御
- 04衝突とオーバーラップの処理
- 05物理グループとワールド境界の利用
活用シーン
- 01トップダウン型の移動実装
- 02プラットフォームジャンプと接地判定
- 03アイテム取得やトリガーの処理
- 04デバッグ時のボディ確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ gamedev-skills/ awesome-gamedev-agent-skills --skill phaser-arcade-physicsインストール後、Claude Code で/phaser-arcade-physicsを入力して読み込まれたか確認します。
同梱ファイルreferences/bodies-and-collision.md
詳細
Phaser 4 Arcade Physics
軽量な Arcade Physics エンジン(AABB の長方形と円のみ)を使って、Phaser ゲームに移動と衝突を追加します。新規プロジェクトでは Phaser 4.2 を対象とします。既存のプロジェクトを編集する前に、インストール済みのメジャーバージョンを確認してください。
使用する場面
- トップダウンまたはプラットフォームゲームでの移動、速度/加速度/重力、跳ね返り、ワールド境界、スプライト、グループ、タイル間の衝突や重なりの解決に使用します。
- シーンで
physics: { default: 'arcade' }を有効にし、コードでthis.physics.add.*、body.setVelocity、またはthis.physics.add.colliderを呼び出す場合に使用します。
使用しない場面: Game の設定、シーン構成、アセットの読み込み、カメラには → phaser-core を使用します。ヒンジ、バネ、複雑なポリゴン、剛体の積み重ねには → Matter physics を使用します(別のエンジンです。Arcade と Matter のボディは相互作用しません)。エンジンに依存しない操作感の調整については physics-tuning を参照してください。
基本的なワークフロー
- ワールドを有効にします。 ゲームまたはシーンの設定で
physics: { default: 'arcade', arcade: { gravity: {...}, debug: true } }を設定します。構築中はdebugをオンにして、ボディの輪郭と速度ベクトルを確認します。 - スプライトにボディを設定します。
this.physics.add.sprite(...)(動的)またはthis.physics.add.staticImage(...)(静的)で作成するか、既存のオブジェクトにthis.physics.add.existing(obj)でアタッチします。 x/yを設定せず、ボディを通じて動かします。setVelocity、setAcceleration、重力、setBounce、setCollideWorldBoundsを使用します。エンジンは各ステップで速度から位置を積分します(すでにフレームレートに依存しない方式です)。- 相互作用を解決します。
this.physics.add.collider(a, b)はボディを分離し、this.physics.add.overlap(a, b, cb)は分離せずに検出します(アイテム取得、トリガー)。反応させるにはコールバックを渡します。 - 複数のオブジェクトをグループ化します。
this.physics.add.group()(動的)またはstaticGroup()(プラットフォーム)を使うと、1 回のコライダー呼び出しですべてのメンバーを処理できます。 - ジャンプ前に
body.onFloor()/body.blocked.downで接地を確認します。debug: trueで実行し、ボディ、接触、境界を確認します。
パターン
1. Arcade Physics を有効にする(ゲーム設定)
const config = {
type: Phaser.AUTO,
width: 800, height: 600,
physics: {
default: 'arcade',
arcade: {
gravity: { x: 0, y: 600 }, // top-down? use { x: 0, y: 0 }
debug: false // true to draw bodies + velocity while building
}
},
scene: [PlayScene]
};
new Phaser.Game(config);
2. トップダウンの移動(入力から速度を設定)
create() {
this.player = this.physics.add.sprite(400, 300, 'player');
this.player.setCollideWorldBounds(true);
this.cursors = this.input.keyboard.createCursorKeys();
}
update() {
const speed = 220;
const body = this.player.body;
body.setVelocity(0); // reset each frame
if (this.cursors.left.isDown) body.setVelocityX(-speed);
if (this.cursors.right.isDown) body.setVelocityX(speed);
if (this.cursors.up.isDown) body.setVelocityY(-speed);
if (this.cursors.down.isDown) body.setVelocityY(speed);
body.velocity.normalize().scale(speed); // keep diagonals same speed
}
3. プラットフォームゲームのジャンプ(重力+接地判定)
create() {
this.player = this.physics.add.sprite(100, 450, 'player');
this.player.setCollideWorldBounds(true);
// Static platforms: one body each, never moved by collisions.
this.platforms = this.physics.add.staticGroup();
this.platforms.create(400, 568, 'ground');
this.physics.add.collider(this.player, this.platforms);
this.cursors = this.input.keyboard.createCursorKeys();
}
update() {
const onGround = this.player.body.blocked.down; // or this.player.body.onFloor()
if (this.cursors.left.isDown) this.player.setVelocityX(-160);
else if (this.cursors.right.isDown) this.player.setVelocityX(160);
else this.player.setVelocityX(0);
if (this.cursors.up.isDown && onGround) this.player.setVelocityY(-450);
}
4. コライダーとオーバーラップ(分離と検出)
// Push apart and react: player vs enemies.
this.physics.add.collider(this.player, this.enemies, (player, enemy) => {
this.handleHit(player, enemy);
});
// Detect without pushing: collect coins. The 4th arg is an optional
// process callback returning a boolean to filter pairs before the main callback.
this.physics.add.overlap(this.player, this.coins, (player, coin) => {
coin.disableBody(true, true); // deactivate + hide
this.registry.inc('score', 10);
});
5. 移動するオブジェクトのグループ
this.bullets = this.physics.add.group({
defaultKey: 'bullet',
maxSize: 30 // pool size; reuse instead of allocating
});
fire(x, y) {
const bullet = this.bullets.get(x, y); // reuses a dead bullet if available
if (!bullet) return;
bullet.enableBody(true, x, y, true, true);
bullet.setVelocityY(-500);
}
注意点
- スプライトが物理演算に反応しない →
this.physics.add.sprite(またはthis.physics.add.existing(obj))ではなくthis.add.spriteで追加されているため、ボディがありません。 sprite.xを直接設定するとエンジンと競合する → 動的ボディはsetVelocity/setAccelerationで動かします。位置を直接書き換えると、コライダーをすり抜けることがあります。- 斜め移動の速度が上がる → X と Y の速度が個別に加算されるため、速度ベクトルを正規化し、意図した速度に合わせて再スケーリングします。
- プラットフォームがプレイヤーに押される →
staticGroupを使うか、動的なプラットフォームでbody.setImmovable(true)を設定します。 onFloor()が常に false になる → ボディには衝突対象が必要です。接地判定の前に地面/プラットフォームとのcolliderを追加し、重力が有効であることを確認します。- 静的ボディを動かした後、衝突判定が古いままになる → 静的ボディは自動同期されません。
body.updateFromGameObject()(またはゲームオブジェクトのrefreshBody())を呼び出します。 - コライダーを毎フレーム追加している →
collider/overlapはupdateではなく、createで一度だけ登録します。
参考資料
- ボディの構造と調整(ドラッグ、跳ね返り、最大速度、カスタム
setSize/setCircle/setOffsetヒットボックス、衝突カテゴリ/マスク、worldboundsイベント)については、references/bodies-and-collision.mdを参照してください。
関連スキル
phaser-core— ゲーム設定、シーン、ローダー、カメラ(前提となるセットアップ)。physics-tuning— エンジンに依存しない操作感(固定タイムステップ、すり抜け、ジッター)。platformer/tower-defense— このスキルを組み合わせて使うジャンル。level-design— これらのボディが衝突するタイル/プラットフォームのジオメトリを配置します。
コメント
Markdown 対応