Claude-skill-registry dev-phaser-physics-arcade
Arcade physics velocity, acceleration, collision, and bounds
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dev-phaser-physics-arcade" ~/.claude/skills/majiayu000-claude-skill-registry-dev-phaser-physics-arcade && rm -rf "$T"
manifest:
skills/data/dev-phaser-physics-arcade/SKILL.mdsource content
Phaser Arcade Physics
"Fast, simple 2D physics for platformers and arcade games."
Before/After: Manual Collision vs Phaser Arcade Physics
❌ Before: Manual AABB Collision
// Manual physics without Phaser interface Box { x: number; y: number; width: number; height: number; vx: number; vy: number; } const player: Box = { x: 100, y: 300, width: 32, height: 48, vx: 0, vy: 0 }; const platforms: Box[] = [ { x: 0, y: 500, width: 800, height: 68 } ]; function checkCollision(a: Box, b: Box): boolean { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; } function updatePhysics(dt: number) { // Apply gravity player.vy += 1000 * dt; // Update position player.x += player.vx * dt; player.y += player.vy * dt; // Check collision with each platform for (const platform of platforms) { if (checkCollision(player, platform)) { // Resolve collision if (player.vy > 0 && player.y + player.height - player.vy * dt <= platform.y) { player.y = platform.y - player.height; player.vy = 0; } } } // World bounds if (player.x < 0) player.x = 0; if (player.x > 800 - player.width) player.x = 800 - player.width; } // Problems: // - Manual collision detection is error-prone // - No proper physics simulation // - Tunneling at high speeds // - No built-in platformer features // - Manual state tracking
✅ After: Phaser Arcade Physics
// Phaser handles physics automatically export class GameScene extends Phaser.Scene { private player!: Phaser.Physics.Arcade.Sprite; create() { // Physics-enabled sprite with built-in collision this.player = this.physics.add.sprite(100, 450, 'player'); this.player.setBounce(0); // No bounce this.player.setCollideWorldBounds(true); // Static platforms group const platforms = this.physics.add.staticGroup(); platforms.create(400, 568, 'ground').setScale(2, 1).refreshBody(); // One line to add collision this.physics.add.collider(this.player, platforms); } update() { // Simple velocity-based movement if (this.cursors.left.isDown) { this.player.setVelocityX(-160); } else if (this.cursors.right.isDown) { this.player.setVelocityX(160); } else { this.player.setVelocityX(0); } // Grounded check built-in if (this.cursors.up.isDown && this.player.body!.touching.down) { this.player.setVelocityY(-330); } } } // Benefits: // - Built-in collision detection (no tunneling) // - Touching detection (grounded, walls) // - World bounds handling // - Proper physics simulation // - Easy platformer features
When to Use This Skill
Use when:
- Implementing platformer games
- Creating collision detection
- Working with velocity and gravity
- Building arcade-style gameplay
- Need simple, performant physics
Quick Start
// Enable arcade physics in game config physics: { default: 'arcade', arcade: { gravity: { y: 1000 }, debug: false } } // Create physics sprite const player = this.physics.add.sprite(400, 300, 'player'); player.setBounce(0.2); player.setCollideWorldBounds(true);
Decision Framework
| Need | Use |
|---|---|
| Platformer | Arcade with gravity |
| Top-down | Arcade without gravity |
| Bouncing objects | |
| Static platforms | |
| Collision detection | |
Progressive Guide
Level 1: Basic Physics Body
export class GameScene extends Phaser.Scene { private player!: Phaser.Physics.Arcade.Sprite; create() { // Create physics sprite this.player = this.physics.add.sprite(400, 300, "player"); // Physics properties this.player.setBounce(0.2); // Bounciness (0-1) this.player.setCollideWorldBounds(true); // Don't leave screen this.player.setDrag(0.1, 0); // Air resistance this.player.setFriction(0.1); // Ground friction this.player.setMaxVelocity(400); // Speed cap // Velocity control this.player.setVelocityX(200); this.player.setVelocityY(-300); this.player.setVelocity(100, 100); // Acceleration this.player.setAccelerationX(50); } }
Level 2: Collision Detection
create() { const player = this.physics.add.sprite(400, 300, 'player'); const platforms = this.physics.add.staticGroup(); // Create platforms platforms.create(400, 568, 'ground').setScale(2, 1).refreshBody(); platforms.create(600, 400, 'platform'); // Player collides with platforms this.physics.add.collider(player, platforms); // Overlap detection (trigger, no collision response) const coins = this.physics.add.group({ defaultKey: 'coin', bounceX: 0.5, bounceY: 0.5 }); this.physics.add.overlap(player, coins, this.collectCoin, undefined, this); } collectCoin(player: Phaser.Types.Physics.Arcade.GameObjectWithBody, coin: any) { coin.disableBody(true, true); // Disable and hide }
Level 3: Platformer Controls
export class GameScene extends Phaser.Scene { private player!: Phaser.Physics.Arcade.Sprite; private cursors!: Phaser.Types.Input.Keyboard.CursorKeys; private jumpKey!: Phaser.Input.Keyboard.Key; create() { this.player = this.physics.add.sprite(100, 450, "player"); this.player.setBounce(0); this.player.setCollideWorldBounds(true); // Setup inputs this.cursors = this.input.keyboard!.createCursorKeys(); this.jumpKey = this.input.keyboard!.addKey("SPACE"); // Platforms const platforms = this.physics.add.staticGroup(); platforms.create(400, 568, "ground").setScale(2).refreshBody(); this.physics.add.collider(this.player, platforms); } update() { // Left/Right movement if (this.cursors.left.isDown) { this.player.setVelocityX(-160); } else if (this.cursors.right.isDown) { this.player.setVelocityX(160); } else { this.player.setVelocityX(0); } // Jump only if touching ground if (this.jumpKey.isDown && this.player.body!.touching.down) { this.player.setVelocityY(-330); } } }
Level 4: Advanced Collision Callbacks
create() { // Collision with process callback (custom collision logic) this.physics.add.collider( this.player, this.enemies, this.playerHitEnemy, this.checkEnemyVulnerable, this ); } // Called to check if collision should happen checkEnemyVulnerable( player: Phaser.Types.Physics.Arcade.GameObjectWithBody, enemy: any ): boolean { const enemySprite = enemy as Phaser.Physics.Arcade.Sprite; // Only collide if enemy is vulnerable return !enemySprite.getData('invincible'); } // Called when collision occurs playerHitEnemy( player: Phaser.Types.Physics.Arcade.GameObjectWithBody, enemy: any ) { const enemySprite = enemy as Phaser.Physics.Arcade.Sprite; // If player is above enemy, kill enemy if (player.body!.velocity.y > 0 && player.y < enemySprite.y - 10) { enemySprite.destroy(); player.setVelocityY(-200); // Bounce } else { // Player dies this.handlePlayerDeath(); } }
Level 5: Custom Physics Components
// Physics component class class PlatformerController { private speed = 160; private jumpForce = -330; private isGrounded = false; constructor( private sprite: Phaser.Physics.Arcade.Sprite, private cursors: Phaser.Types.Input.Keyboard.CursorKeys, private jumpKey: Phaser.Input.Keyboard.Key ) { this.enableDoubleJump(); } update() { // Horizontal movement if (this.cursors.left.isDown) { this.sprite.setVelocityX(-this.speed); this.sprite.setFlipX(true); } else if (this.cursors.right.isDown) { this.sprite.setVelocityX(this.speed); this.sprite.setFlipX(false); } else { this.sprite.setVelocityX(0); } // Jump if (this.jumpKey.isDown && this.isGrounded) { this.sprite.setVelocityY(this.jumpForce); this.isGrounded = false; } } onGrounded() { this.isGrounded = true; } private enableDoubleJump() { this.jumpKey.on('down', () => { if (!this.isGrounded && this.sprite.body!.velocity.y > -200) { this.sprite.setVelocityY(this.jumpForce * 0.8); } }); } } // In scene create() { const controller = new PlatformerController( this.player, this.cursors, this.jumpKey ); this.physics.add.collider(this.player, platforms, () => { controller.onGrounded(); }); } update() { controller.update(); }
Anti-Patterns
❌ DON'T:
- Use Matter physics for simple platformers - Arcade is faster
- Set position directly on physics bodies - use velocity
- Forget to call
after scaling static objectsrefreshBody() - Use overlap when collider is needed
- Disable physics bodies instead of removing from scene
- Mix pixel and meter units arbitrarily
✅ DO:
- Use Arcade for platformers, top-down games
- Apply forces/velocity for movement
- Refresh body after scale/position changes
- Use proper collision types (collider vs overlap)
- Remove bodies from physics world when destroyed
- Keep units consistent (pixels)
Code Patterns
One-Way Platforms
create() { const platforms = this.physics.add.staticGroup(); // Create one-way platform const platform = platforms.create(400, 400, 'platform'); platform.checkCollision.down = false; // Can jump through from below platform.checkCollision.up = true; // Lands on top }
Body Size Adjustment
const player = this.physics.add.sprite(400, 300, "player"); // Adjust body size (smaller than sprite) player.body!.setSize(20, 40); player.body!.setOffset(6, 8); // Center the body // Disable body on one side player.body!.checkCollision.up = false;
Moving Platform
export class MovingPlatform extends Phaser.Physics.Arcade.Image { constructor( scene: Phaser.Scene, x: number, y: number, texture: string, private startX: number, private endX: number, ) { super(scene, x, y, texture); scene.add.existing(this); scene.physics.add.existing(this, false); // false = static this.setVelocityX(50); this.scene.events.on("update", this.updatePlatform, this); } updatePlatform() { if (this.x >= this.endX) { this.setVelocityX(-50); } else if (this.x <= this.startX) { this.setVelocityX(50); } } }
Checklist
- Physics enabled in game config
- Bodies properly sized (offset from sprite)
- Static bodies use
staticGroup() - Dynamic bodies use
physics.add.sprite() - Colliders/overlaps configured
- World bounds enabled if needed
- Refresh body called after scale
Physics Body Properties
| Property | Type | Description |
|---|---|---|
| Vector2 | Current velocity |
| Vector2 | Applied acceleration |
| Vector2 | Deceleration over time |
| Vector2 | Applied gravity force |
| number | Bounciness (0-1) |
| number | Surface friction |
| Vector2 | Maximum speed cap |
| boolean | Whether gravity affects body |
| boolean | Body cannot be pushed |
Reference
- Arcade Physics Docs — Official docs
- Physics Body API — Body properties