gamedev-skills/awesome-gamedev-agent-skills

phaser-arcade-physics

Use Phaser 4 Arcade Physics: enable the world, give sprites bodies, set velocity/acceleration/gravity, and resolve collisions with colliders, overlaps, groups, and world bounds.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill phaser-arcade-physics

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Phaser 4 Arcade Physics

Add movement and collision to a Phaser game with the lightweight Arcade Physics engine (AABB rectangles and circles only). Targets Phaser 4.2 for new projects; inspect the installed major before editing an existing project.

When to use

  • Use for top-down or platformer movement, velocity/acceleration/gravity, bouncing,

world bounds, and collision/overlap resolution between sprites, groups, and tiles.

  • Use when the scene enables 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.

Core workflow

  1. Enable the world. Set `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.

  1. Give a sprite a body. Create it with this.physics.add.sprite(...) (dynamic)

or this.physics.add.staticImage(...) (static), or attach to an existing object with this.physics.add.existing(obj).

  1. Drive it through the body, not by setting `x`/`y`. Use setVelocity,

setAcceleration, gravity, setBounce, and setCollideWorldBounds. The engine integrates position from velocity each step (already frame-rate independent).

  1. Resolve interactions. 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.

  1. Group many objects. Use this.physics.add.group() (dynamic) or

staticGroup() (platforms) so one collider call handles all members.

  1. Check ground contact with body.onFloor() / body.blocked.down before

jumping. Run with debug: true and confirm bodies, contacts, and bounds.

Patterns

1. Enable Arcade Physics (game config)

js
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. Top-down movement (velocity from input)

js
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. Platformer jump (gravity + ground check)

js
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. Colliders vs overlaps (separate vs detect)

js
// 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. A group of moving objects

js
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 an inactive bullet if available
  if (!bullet) return;                       // pool is full: every bullet is active
  bullet.enableBody(true, x, y, true, true);
  bullet.setVelocityY(-500);
}

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

Pitfalls

  • Sprite ignores physics → it was added with this.add.sprite instead of

this.physics.add.sprite (or this.physics.add.existing(obj)), so it has no body.

  • Setting `sprite.x` directly fights the engine → move dynamic bodies with

setVelocity/setAcceleration. Direct position writes can tunnel through colliders.

  • Diagonal movement is faster → independent X and Y velocities add up; normalise

the velocity vector and rescale to the intended speed.

  • Platforms get pushed by the player → use a 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. Standing on an ordinary dynamic body does not count as blocked; make platforms static, immovable, or non-pushable (platform.setPushable(false)).

  • Moved a static body but collisions are stale → static bodies don't auto-sync;

call body.updateFromGameObject() (or refreshBody() on the game object).

  • Collider added every frame → register collider/overlap once in create,

not in update.

  • Fast bullets pass through thin walls → Arcade has no swept collision; a body

that moves farther than a wall's thickness in one physics step skips it. Thicken the wall's body, cap speed with setMaxVelocity, or raise the step rate (arcade: { fps: 120 }, default 60) at extra CPU cost.

  • Bodies pass through each other after adding collision categories → a pair only

collides when each side's mask includes the other's category, and untouched bodies keep mask 1. Widen the other side's mask too, and set groups and their members separately (see the reference).

  • Drag does nothing while a key is held → Arcade applies drag only on an axis

with zero acceleration; set the acceleration to 0 when input stops.

References

  • For body anatomy and tuning (drag, bounce, max velocity, custom setSize/

setCircle/setOffset hitboxes, collision categories/masks, and worldbounds events), read references/bodies-and-collision.md.

Related skills

  • 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.
from this repository

More skills

All skills
gamedev-skills
Community

godot-3d-essentials

Set up a Godot 4.7 3D scene: Node3D transforms, Camera3D, lighting (DirectionalLight3D/OmniLight3D), WorldEnvironment for sky/ambient/tonemap/post, MeshInstance3D materials, and GridMap for tile-based 3D levels. Use when building a 3D scene in a Godot project, placing cameras/lights, configuring environment and post-processing, or working with Node3D/.tscn 3D content and GridMap.

1h installs
14
GitHub stars
6.3K
Updated
Oct 28
gamedev-skills
Community

godot-animation

Animate in Godot 4.7 three ways: AnimationPlayer for keyframed clips (incl. Call Method tracks), AnimationTree with state machines and blend spaces for character animation, and Tween for short procedural/UI tweens via createtween(). Use when working with AnimationPlayer/AnimationTree nodes in a .tscn, blending character states, sprite-sheet animation, or code-driven Tweens.

1h installs
13
GitHub stars
6.3K
Updated
Oct 28
gamedev-skills
Community

godot-audio

Play and mix audio in Godot 4.7: AudioStreamPlayer (2D/3D variants), audio buses with volume/mute and effects, music vs SFX routing, db/linear volume, and precise sync-to-beat playback timing. Use when playing sounds or music in a Godot project, routing AudioStreamPlayer nodes to buses, adjusting bus volume via AudioServer, or syncing gameplay to the beat.

1h installs
13
GitHub stars
6.3K
Updated
Oct 28
gamedev-skills
Community

godot-multiplayer

Build networked games with Godot 4.7 high-level multiplayer: set up an ENetMultiplayerPeer server/client, define RPCs with the @rpc annotation (call via rpc()/rpcid()), set per-node multiplayer authority, and replicate state with MultiplayerSpawner and MultiplayerSynchronizer. Use when adding multiplayer/networking to a Godot project, writing @rpc functions, or syncing player/world state across peers.

1h installs
13
GitHub stars
6.3K
Updated
Oct 28