Arcade Physics in Phaser
Physics makes games feel real. When a character jumps and gravity pulls them back down, when a bullet hits a wall and stops, when a player bumps into an enemy and takes damage, these interactions are all driven by the physics engine. Phaser's Arcade Physics system is designed to handle these interactions efficiently, processing hundreds of collision checks per frame while keeping the code simple and readable.
Enable Arcade Physics in Your Game Config
Arcade Physics is activated through the game configuration object. Set physics.default to "arcade" and configure the global gravity under physics.arcade.gravity. For a side-scrolling platformer, set gravity.y to a positive value between 200 and 500. Higher values create heavier, more grounded movement, while lower values feel floaty and spacey. For a top-down game, set both gravity.x and gravity.y to 0 since characters should not fall in any direction.
Enable debug visualization during development by setting physics.arcade.debug to true. This draws the collision boundaries of all physics bodies as colored rectangles and circles overlaid on your game. Green outlines show static bodies, blue outlines show dynamic bodies, and red highlights indicate active collisions. Debug mode is invaluable for understanding why a collision is not working as expected, such as when a body is too small, offset from the sprite, or overlapping with an unintended object.
The physics configuration also supports settings for timeScale, which slows down or speeds up the physics simulation independently of rendering, and tileBias, which affects collision resolution with tilemap layers. Most games can leave these at their default values, but they provide useful controls for bullet-time effects and fine-tuning tilemap collision behavior.
Create Dynamic and Static Physics Bodies
Every physics-enabled object in Arcade Physics has a body, which is an invisible rectangle or circle that defines where the object exists in the physics world. Dynamic bodies move, respond to gravity, and bounce off other bodies. Static bodies are immovable and do not respond to forces, making them ideal for platforms, walls, ground tiles, and any fixed element of the environment.
Create a dynamic body by adding a sprite through the physics factory: this.physics.add.sprite(x, y, textureKey). The returned sprite automatically has a physics body with default settings. You can then customize the body by setting properties like bounce, which controls how much velocity is preserved after a collision (0 for no bounce, 1 for perfect elastic bounce), and collideWorldBounds, which keeps the body inside the game area.
Create a static body using this.physics.add.staticSprite(x, y, textureKey) or by adding sprites to a static group. Static bodies are computationally cheaper than dynamic bodies because the physics engine does not need to update their position, check gravity, or apply forces each frame. Use static bodies for everything that does not need to move.
The body size does not have to match the sprite size. Call body.setSize(width, height) to make the collision area smaller than the visual sprite, which is common for player characters where you want the hitbox to be tighter than the full sprite image. Use body.setOffset(x, y) to center the smaller body within the sprite. A well-tuned hitbox makes the game feel fair because near-misses read as misses rather than frustrating collisions.
Control Movement with Velocity and Acceleration
The most direct way to move a physics body is by setting its velocity. Call body.setVelocityX(value) for horizontal movement and body.setVelocityY(value) for vertical movement. Positive X moves right, negative X moves left. Positive Y moves down, negative Y moves up. Setting velocity directly gives instant, responsive movement that feels snappy and precise.
For smoother, more natural movement, use acceleration instead of direct velocity. Set body.setAccelerationX(value) to gradually increase the body's speed in that direction, and set body.setDrag(value) to slow it down when acceleration stops. This creates a character that speeds up gradually and slides to a stop, which feels more physical and weighty. Drag acts as friction, and higher drag values make the character stop faster.
MaxVelocity caps how fast a body can move, preventing runaway acceleration from pushing objects to unreasonable speeds. Set body.setMaxVelocity(x, y) to define speed limits independently for horizontal and vertical movement. This is particularly important for falling objects, where gravity continuously increases vertical velocity each frame. Without a max velocity, a character falling for several seconds would reach extreme speeds that break collision detection.
Jumping in a platformer combines vertical velocity with gravity. When the player presses the jump button and the character is on the ground, set a negative vertical velocity to launch upward. Gravity continuously reduces this velocity, stops the character at the peak, and accelerates them back down. The jump height depends on the initial velocity magnitude and the gravity strength. Typical values range from -250 to -400 for vertical velocity with gravity between 300 and 600.
Set Up Collision and Overlap Detection
Phaser distinguishes between collisions and overlaps. A collision prevents two bodies from passing through each other, applying physical separation so they push apart. An overlap detects when two bodies occupy the same space but does not prevent it. Use colliders for solid objects like platforms, walls, and enemies the player bumps against. Use overlaps for triggers like collectible items, damage zones, and level exit areas.
Create a collider with this.physics.add.collider(objectA, objectB, callback, processCallback, context). The objectA and objectB parameters can be individual sprites, groups, or arrays. The callback fires when the collision occurs, receiving the two colliding objects as arguments. The optional processCallback runs before separation and returns a boolean that determines whether the collision should actually be resolved, useful for conditional collision like one-way platforms.
Create an overlap with this.physics.add.overlap(objectA, objectB, callback, processCallback, context). The callback fires every frame that the two objects are overlapping. Inside the callback, you typically perform a game action and then disable or destroy one of the objects. For collectibles, call item.disableBody(true, true) to remove the item from both the physics simulation and the display, making it disappear when the player touches it.
Collision callbacks receive the two colliding objects as arguments, which lets you write generic collision handlers. For example, a single collider between the player and an enemy group can handle damage for all enemy types, with the callback checking the enemy's type or damage value to determine how much health the player loses. This pattern keeps your code clean as the number of interacting objects grows.
Use Physics Groups for Object Management
Physics groups collect multiple bodies of the same type, such as bullets, enemies, coins, or platforms, into a single container that can participate in collisions as a unit. Create a dynamic group with this.physics.add.group() and a static group with this.physics.add.staticGroup(). Add members with group.create(x, y, key) or group.add(existingSprite).
Groups support object pooling, which reuses inactive objects instead of creating and destroying them repeatedly. This is critical for projectiles and particles where hundreds of objects might be created per second. Set the group's maxSize to limit how many objects it holds, and retrieve inactive objects with group.get() which returns a dormant member that you reactivate, reposition, and launch. When the object is done, disable it with disableBody so the group can reuse it later.
Group-wide property changes let you configure all members at once. Pass a configuration object when creating the group to set default values for gravity, velocity, bounce, drag, and collideWorldBounds. You can also call group.setVelocityX(value) to change the velocity of every active member simultaneously, which is useful for scrolling obstacles, wave patterns, or synchronized enemy movement.
Setting up a collider between a group and another object or group checks all active members automatically. This means one line of code handles collision between the player and every enemy in the game, regardless of how many enemies exist. Phaser internally iterates over all active group members and performs pairwise collision checks, with spatial partitioning optimizations to skip bodies that are too far apart to interact.
Optimize Physics Performance
Arcade Physics is fast by design, but poorly managed physics can still cause frame drops in complex games. The primary performance factor is the number of active physics bodies. Each body must be checked against potential collision partners every frame, and the cost grows with the number of bodies. Keep inactive objects disabled with disableBody rather than leaving them active but off-screen.
Body size tuning reduces the number of false-positive collision candidates. Use the tightest possible collision bodies for your objects, and avoid oversized bodies that trigger unnecessary collision checks. For elongated objects like bullets or beams, consider using raycasting instead of a physics body, as a single ray check is cheaper than maintaining a fast-moving body that can tunnel through thin objects.
The physics overlap check uses the broadphase to quickly eliminate pairs that cannot possibly collide based on their positions. For scenes with many objects, consider dividing them into logical groups and only checking collisions between groups that can actually interact. Checking enemies against the player group and bullets against the enemy group is far more efficient than checking everything against everything.
When objects leave the screen, either disable or destroy them. Bullets that fly off-screen, enemies that fall below the level, and particles that have finished their animation should be cleaned up promptly. Set up world bounds events or screen boundary checks in the update loop to catch runaway objects. For object-pooled groups, this means disabling the body and returning the object to the pool rather than creating garbage for the JavaScript engine to collect.
Arcade Physics handles most 2D game mechanics with just velocity, gravity, and collision callbacks. Use static bodies for fixed objects, dynamic bodies for moving ones, groups for efficient batch collision, and object pooling for frequently created objects like bullets and particles.