Skip to content
Back to skills

Phaser Arcade Physics

ASecurity

Phaser 4 Arcade Physics movement and collision: bodies, velocity, gravity, colliders vs overlaps, groups and bullet pools. Use for a Phaser platformer or top-down controller, or a sprite that ignores physics, onFloor() always false or bodies passing through walls. Not for scenes and the loader (`phaser-core`), coyote time (`platformer`) or tunnelling theory (`physics-tuning`).

  • 8,520 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 5, 2026
ai-agentsgoreactspringgitapi

Works with

  • cursor
  • cli
  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned November 12, 2026

npx -y skills add gamedev-skills/awesome-gamedev-agent-skills --skill phaser-arcade-physics --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Phaser Arcade Physics?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Phaser Arcade Physics
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/gamedev-skills-phaser-arcade-physics/badge)](https://www.skillsdirectory.com/skills/gamedev-skills-phaser-arcade-physics)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: phaser-arcade-physics
description: >
  Phaser 4 Arcade Physics movement and collision: bodies, velocity, gravity, colliders vs
  overlaps, groups and bullet pools. Use for a Phaser platformer or top-down controller, or a
  sprite that ignores physics, onFloor() always false or bodies passing through walls. Not for
  scenes and the loader (`phaser-core`), coyote time (`platformer`) or tunnelling theory
  (`physics-tuning`).
---

# Phaser 4 Arcade Physics

Moves and collides sprites with Phaser's Arcade engine: axis-aligned rectangles and circles,
no rotation in collision, no joints. That is enough for most platformers, shooters and
top-down games, and it is fast. New projects target **Phaser 4.2**; check the installed major
before editing an existing project. If the game needs hinges, springs, slopes or rotated
polygons, Matter physics is the separate engine for that, and its bodies never collide with
Arcade bodies.

## When to use

- Platformer or top-down movement, gravity, bouncing, world bounds, and collision or overlap
  between sprites, groups and tilemap layers.
- The config has `physics: { default: 'arcade' }`, or code calls `this.physics.add.*`,
  `body.setVelocity` or `this.physics.add.collider`.
- Not for scene structure and loading (`phaser-core`), jump-feel rules such as coyote time
  (`platformer`), or fixed timestep and tunnelling in general (`physics-tuning`).

## Workflow

1. **Enable the world with debug drawing on**: `physics: { default: 'arcade', arcade: {
   gravity: { x: 0, y: 600 }, debug: true } }`. Body outlines and velocity lines answer most
   "why didn't it collide" questions at a glance. Turn debug off before release.
2. **Create bodies through the physics factory**: `this.physics.add.sprite` (dynamic),
   `this.physics.add.staticImage` or `staticGroup` (walls and ground), or
   `this.physics.add.existing(obj)` for an object you already made.
3. **Move dynamic bodies through the body** with velocity, acceleration and gravity. Writing
   `x`/`y` directly teleports the body past colliders.
4. **Register each `collider` and `overlap` once in `create`.** A collider separates bodies;
   an overlap only reports contact (pickups, triggers, hurtboxes).
5. **Use groups** so one collider covers many objects, and pool projectiles with `maxSize`.
6. **Verify** with the probe in [Verify](#verify).

## Patterns

### 1. Enable Arcade Physics

```js
const config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
  physics: {
    default: 'arcade',
    arcade: {
      gravity: { x: 0, y: 600 }, // top-down games use { x: 0, y: 0 }
      debug: true,               // body outlines and velocity while building
    },
  },
  scene: [PlayScene],
};
```

### 2. Top-down movement

```js
update() {
  const speed = 220;
  const body = this.player.body;
  body.setVelocity(0);
  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); // diagonals at the same speed (zero stays zero)
}
```

### 3. Platformer with a ground check

```js
create() {
  this.platforms = this.physics.add.staticGroup();
  this.platforms.create(400, 568, 'ground');

  this.player = this.physics.add.sprite(100, 450, 'player');
  this.player.setCollideWorldBounds(true);
  this.player.body.setSize(20, 36, true); // hitbox tighter than the art, centred

  this.physics.add.collider(this.player, this.platforms); // once, here
  this.cursors = this.input.keyboard.createCursorKeys();
}

update() {
  const onGround = this.player.body.blocked.down; // same as body.onFloor()
  const dir = (this.cursors.right.isDown ? 1 : 0) - (this.cursors.left.isDown ? 1 : 0);
  this.player.setVelocityX(dir * 160);
  if (this.cursors.up.isDown && onGround) this.player.setVelocityY(-450);
}
```

### 4. Collider vs overlap

```js
// Push apart, then react.
this.physics.add.collider(this.player, this.enemies, (player, enemy) => this.hurt(player, enemy));

// Detect only. The optional 4th argument returns false to skip a pair before the callback.
this.physics.add.overlap(this.player, this.coins, (player, coin) => {
  coin.disableBody(true, true); // deactivate and hide; the group can reuse it
  this.registry.inc('score', 10);
});
```

### 5. Pooled projectiles

```js
create() {
  this.bullets = this.physics.add.group({ defaultKey: 'bullet', maxSize: 30 });
}

fire(x, y) {
  const bullet = this.bullets.get(x, y); // an inactive member, or a new one under maxSize
  if (!bullet) return;                   // every bullet is in flight
  bullet.enableBody(true, x, y, true, true);
  bullet.body.setAllowGravity(false);
  bullet.setVelocityY(-500);
}

update() {
  // Return off-screen bullets to the pool, or firing stops after 30 shots.
  for (const bullet of this.bullets.getChildren()) {
    if (bullet.active && bullet.y < -32) bullet.disableBody(true, true);
  }
}
```

## Verify

1. `npm run build` (or `npx tsc --noEmit`) passes.
2. Probe the running game. If `phaser-core`'s headless smoke script is in use, put this body
   in its `page.evaluate(() => { ... })` after a two-second wait, adjusting the scene key and
   object names:

```js
const s = window.game.scene.getScene('play');
return {
  bodies: s.physics.world.bodies.size,          // dynamic bodies alive
  staticBodies: s.physics.world.staticBodies.size,
  playerOnFloor: s.player.body.blocked.down,    // true once the player has landed
  playerY: Math.round(s.player.y),
};
```

   Expect `playerOnFloor: true` and a `playerY` resting on the ground for a platformer, and a
   body count that stays flat while firing (the pool is recycling).
3. With `debug: true`, take a screenshot and check that hitboxes sit on the art. Without
   browser automation, ask the user to run with `debug: true` and report whether the outlines
   match the sprites and where the player stops.

## Gotchas

- **Sprite ignores physics** → it was made with `this.add.sprite`, so it has no body. Use
  `this.physics.add.sprite` or `this.physics.add.existing(obj)`.
- **`onFloor()` is always false** → nothing to land on: add the `collider` with the ground,
  and check gravity is on. Landing on an ordinary dynamic body does not set `blocked`; make
  platforms static, immovable (`setImmovable(true)`) or non-pushable (`setPushable(false)`).
- **The player shoves platforms around** → they are dynamic bodies; use a `staticGroup`, or
  `setImmovable(true)` for moving platforms.
- **A static body moved but collides at the old spot** → static bodies do not follow their
  game object. Call `body.updateFromGameObject()` (or `refreshBody()` on the object).
- **Fast bullets pass through thin walls** → Arcade has no swept collision, so a body that
  moves farther than a wall's thickness in one step skips it. Thicken the wall's body, cap
  speed with `setMaxVelocity`, or raise `arcade.fps` above its default 60 at CPU cost.
- **Bodies stop colliding after you add a collision category** → a pair collides only when
  each side's mask contains the other's category, and untouched bodies keep mask `1`. Widen
  the other side's mask too, and set a group and its members separately (see the reference).
- **Drag does nothing while a key is held** → Arcade applies drag only on an axis with zero
  acceleration; set acceleration to 0 when input stops.
- **Colliders multiply and the game slows down** → `collider`/`overlap` was called in
  `update`, adding a new one every frame. Register once in `create`; disable with
  `collider.active = false`.
- **The pool stops handing out bullets** → members were hidden but never disabled, so they
  still count as active. Recycle with `disableBody(true, true)`.

## References

- Read [`references/bodies-and-collision.md`](references/bodies-and-collision.md) when tuning
  drag, bounce or max velocity, shaping hitboxes with `setSize`/`setCircle`/`setOffset`,
  filtering pairs with collision categories or a process callback, reading `touching` vs
  `blocked`, or listening for `worldbounds` events.

## Related skills

- `phaser-core`: game config, scenes, loader and cameras.
- `platformer`: coyote time, jump buffering, variable jump height and level structure.
- `physics-tuning`: engine-neutral feel, timestep, tunnelling and jitter.
- `level-design`: the tile and platform layouts these bodies collide with.

## Version notes

Last verified: 2026-11-11 against Phaser 4.2.1 (npm `latest`, published 2026-07-09).

- Checked in the v4.2.1 source: `arcade.fps` defaults to 60 and `fixedStep` to true; bodies,
  static bodies and static groups start in category 1 with mask 1; a dynamic group's mask is
  all bits; `nextCategory()` allows 32 categories; drag applies only at zero acceleration.
- Sources: [Arcade World.js](https://github.com/phaserjs/phaser/blob/v4.2.1/src/physics/arcade/World.js),
  [Arcade Body.js](https://github.com/phaserjs/phaser/blob/v4.2.1/src/physics/arcade/Body.js),
  `npm view phaser dist-tags`.

Files in this skill

  • SKILL.md6.8 KB
  • references/bodies-and-collision.md4.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in ai-agents →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.