From workflows
Adds Arcade Physics movement, gravity, velocity, and collision/overlap resolution to Phaser 3 games. Use for platformers, top-down controllers, or any scene with this.physics.
How this skill is triggered — by the user, by Claude, or both
Slash command
/workflows:phaser-arcade-physicsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Add movement and collision to a Phaser 3 game with the lightweight **Arcade
Add movement and collision to a Phaser 3 game with the lightweight Arcade Physics engine (AABB rectangles and circles only). Targets Phaser 3.90.
physics: { default: 'arcade' } and code calls
this.physics.add.*, body.setVelocity, or this.physics.add.collider.When not to use: the Game config, scene structure, asset loading, or
cameras → use phaser-core. Hinges, springs, complex polygons, or stacking
rigid bodies → use Matter physics (a different engine; Arcade and Matter bodies
do not interact). For engine-agnostic feel tuning see physics-tuning.
physics: { default: 'arcade', arcade: { gravity: {...}, debug: true } } in the game or scene config. Turn debug on while
building to see body outlines and velocity vectors.this.physics.add.sprite(...) (dynamic)
or this.physics.add.staticImage(...) (static), or attach to an existing object
with this.physics.add.existing(obj).x/y. Use setVelocity,
setAcceleration, gravity, setBounce, and setCollideWorldBounds. The engine
integrates position from velocity each step (already frame-rate independent).this.physics.add.collider(a, b) separates bodies;
this.physics.add.overlap(a, b, cb) detects without separating (pickups,
triggers). Pass a callback to react.this.physics.add.group() (dynamic) or
staticGroup() (platforms) so one collider call handles all members.body.onFloor() / body.blocked.down before
jumping. Run with debug: true and confirm bodies, contacts, and bounds.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);
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
}
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);
}
// 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);
});
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.add.sprite instead of
this.physics.add.sprite (or this.physics.add.existing(obj)), so it has no body.sprite.x directly fights the engine → move dynamic bodies with
setVelocity/setAcceleration. Direct position writes can tunnel through colliders.staticGroup, or set
body.setImmovable(true) on a dynamic platform.onFloor() is always false → the body needs something to collide with; add the
collider against the ground/platforms before checking, and ensure gravity is on.body.updateFromGameObject() (or refreshBody() on the game object).collider/overlap once in create,
not in update.setSize/
setCircle/setOffset hitboxes, collision categories/masks, and worldbounds
events), read references/bodies-and-collision.md.phaser-core — game config, scenes, loader, cameras (the prerequisite setup).physics-tuning — engine-agnostic feel (fixed timestep, tunneling, jitter).platformer / tower-defense — genres that compose this skill.level-design — laying out tile/platform geometry these bodies collide with.npx claudepluginhub gamedev-skills/awesome-gamedev-agent-skills --plugin gamedevConfigures Arcade Physics in Phaser 4: gravity, collisions, velocity, bounce, hitbox sizing, and static/dynamic body creation.
Creates and refactors Phaser 3 browser games with scenes, physics, tilemaps, animations, input, audio, camera, and performance fixes.
Sets up Phaser 3 game config, scene lifecycle, asset loading, cameras, and cross-scene communication. For building or debugging Phaser 3 games.