Arcade physics velocity, acceleration, collision, and bounds
BY feliperybaUPDATED Oct 27, 2026
INTENDED FOR◈OpenClawInstall in a listed agent.
instructions.md
---
name: dev-phaser-physics-arcade
description: Arcade physics velocity, acceleration, collision, and bounds
---
# Phaser Arcade Physics
> "Fast, simple 2D physics for platformers and arcade games."
## Before/After: Manual Collision vs Phaser Arcade Physics
### ❌ Before: Manual AABB Collision
```typescript
// 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
```typescript
// 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
```typescript
// 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 | `setBounce(0.5)` |
| Static platforms | `this.physics.add.staticGroup()` |
| Collision detection | `this.physics.add.collider()` |
## Progressive Guide
### Level 1: Basic Physics Body
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
// 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 `refreshBody()` after scaling static objects
- 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
```typescript
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
```typescript
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
```typescript
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 |
| -------------- | ------- | ---------------------------- |
| `velocity` | Vector2 | Current velocity |
| `acceleration` | Vector2 | Applied acceleration |
| `drag` | Vector2 | Deceleration over time |
| `gravity` | Vector2 | Applied gravity force |
| `bounce` | number | Bounciness (0-1) |
| `friction` | number | Surface friction |
| `maxVelocity` | Vector2 | Maximum speed cap |
| `allowGravity` | boolean | Whether gravity affects body |
| `immovable` | boolean | Body cannot be pushed |
## Reference
- [Arcade Physics Docs](https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.ArcadePhysics.html) — Official docs
- [Physics Body API](https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.Body.html) — Body properties
---
name: dev-phaser-physics-arcade
description: Arcade physics velocity, acceleration, collision, and bounds
---
# Phaser Arcade Physics
> "Fast, simple 2D physics for platformers and arcade games."
## Before/After: Manual Collision vs Phaser Arcade Physics
### ❌ Before: Manual AABB Collision
```typescript
// 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
```typescript
// 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
```typescript
// 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 | `setBounce(0.5)` |
| Static platforms | `this.physics.add.staticGroup()` |
| Collision detection | `this.physics.add.collider()` |
## Progressive Guide
### Level 1: Basic Physics Body
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
// 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 `refreshBody()` after scaling static objects
- 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
```typescript
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
```typescript
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
```typescript
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 |
| -------------- | ------- | ---------------------------- |
| `velocity` | Vector2 | Current velocity |
| `acceleration` | Vector2 | Applied acceleration |
| `drag` | Vector2 | Deceleration over time |
| `gravity` | Vector2 | Applied gravity force |
| `bounce` | number | Bounciness (0-1) |
| `friction` | number | Surface friction |
| `maxVelocity` | Vector2 | Maximum speed cap |
| `allowGravity` | boolean | Whether gravity affects body |
| `immovable` | boolean | Body cannot be pushed |
## Reference
- [Arcade Physics Docs](https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.ArcadePhysics.html) — Official docs
- [Physics Body API](https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.Body.html) — Body properties
COMPATIBILITY & REFERENCES
Platform guidance
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.
Resource notes updated 2026-10-27 · Original instructions by feliperyba
Creates comprehensive frontend UI/UX designs including user interfaces, design systems, component libraries, responsive layouts, and accessibility implementations. Produces wireframes, mockups, design specifications, and implementation guidelines. Use when designing user interfaces, creating desi...
Expert in building scalable design systems with Atomic Design, design tokens, and theming infrastructure. Use when creating component libraries, implementing dark mode, or establishing typography and color systems. Covers multi-brand support, Storybook-driven development, and accessibility-first ...
Use when implementing Liquid Glass effects, reviewing UI for Liquid Glass adoption, debugging visual artifacts, optimizing performance, or requesting expert review of Liquid Glass implementation - provides comprehensive design principles, API patterns, and troubleshooting guidance from WWDC 2025....