A first look at the Arcade Physics 2 API for Lazer.

Article by Richard Davey. Posted on 17th Jun 2016.   @photonstorm

image

I asked Felipe to put together something describing the work he's been doing on the Arcade Physics 2 API, and this is what he wrote. This is available for testing right now in the Lazer GitHub repo, and you can run all the examples seen in this article. Full details are at the end.

Description

The new implementation for Arcade has come with a lot of experimentation and internal testing. The main approach I had when I started implementing the system was it should be fast and that it must support convex polygon detection and solving. Usually games have multiple objects colliding so the approach I took for Arcade 2 was to avoid single collision testing and instead do batch collision requests. This means there are some important changes in the API compared to Arcade 1.

Systems

The new implementation splits different functionalities into systems. Systems in Arcade 2 generally work independently from each other and each one at different times of execution. For example the system in charge of updating bodies properties will run before the system in charge of handling collision and solving it. The three main systems that are used in Arcade 2 are Physics System, Collision System and Collision Callback.

Physics System

The job of the physics system is to update all the registered bodies. This means doing all the calculation for handling velocity, acceleration and gravity. This also applies for angular movements. Finally the position data is updated and ready for the use of the Collision System.

The main function exposed by the physics system is UpdatePhysics.

function UpdatePhysics(physicsStep)

UpdatePhysics requires you to pass the current physics step. This function is called first before any collision related function.

image

Collision System

The collision system is the most complex one and also the one with the most CPU intensive task. The first step of the system is to categorize collisions. The current categories are:

  • Polygon to Polygon Overlap.
  • Dynamic Polygon to Dynamic Polygon Correction.
  • Static Polygon to Dynamic Polygon Correction.
  • AABB to AABB Overlap.
  • Dynamic AABB to Dynamic AABB Correction.
  • Static AABB to Dynamic AABB Correction.

Once all collision requests are categorized a call to the function UpdateCollisions must be done to evaluate and resolve all of them. The UpdateCollisions function is very simple and it looks like this:

function UpdateCollisions() {
    ...
    SolveAABBOverlap();
    SolvePolygonOverlap();
    SolveStaticAABBCollision();
    SolveStaticPolygonCollision();
    SolveDynamicAABBCollision();
    SolveDynamicPolygonCollision();
    ...
}

What it does is go through each category of collision type and solve them. This allow us to avoid multiple branching when trying to detect which type of collision we must test.

The collision system exposes two basic functions:

function Collide(bodyA, bodyB, callback)
function Overlap(bodyA, bodyB, callback)

Collide and Overlap look very similar to Arcade 1 collision functions but internally they work completely different.

Collide will actually separate two colliding bodies and apply any physical properties they have like bounce, friction or mass.

Overlap will only evaluate if two bodies are overlapping and tell the collision callback system to emit a callback function for the overlap request.

Collision Callback System

The main job of the collision callback system is registering callbacks for overlaps and collision tests and dispatching them once the collision system has finished evaluating and solving collisions. Basically when you call the Collide function the collision system internally RegisterCollisionCallback function which pushes the callback into a stack. Collision Callback System doesn’t expose any functionality as it’s used internally by the Collision System.

Colliders

Arcade 2 introduces the concept of colliders. This is mostly because we can have different shapes of bodies. The main current three colliders are Polygon Collider, Rectangle Collider and AABB Collider.

Polygon Collider

A polygon collider defines an abstract representation of polygon data used by the collision system to solve Polygon to Polygon category collisions.

The way you construct a polygon collider is by passing and array with a polygon vertex data. A note that is very important for this first version of Arcade 2 is that ALL polygon data MUST be defined in counterclockwise order. This might change on further updates.

The collider constructor looks like this and it requires an array of vertices as an argument.

PolygonCollider(vertices);

Here is an example of how it would look:

new PolygonCollider([
            // X , Y
            [-228, -50],
            [-228, -50 + 100],
            [-228 + 456, -50 + 100],
            [128, -90]
]);

As you see the argument passed to the constructor is an array of arrays. It can also be constructed using Lazer’s Vec2 class. Another thing to have in mind is that polygons require at least 3 vertices.

This collider also has a couple of properties and functions that can be used to access internal polygon data.

// Returns the X value of a vertex
getX(index)
// Returns the Y value of a vertex
getY(index)
// How many vertices does the polygon have
vertexCount

image

Rectangle Collider

The Rectangle collider extends from Polygon Collider. It has the same properties but it makes it easier to create rectangles that can be rotated.

The Rectangle collider constructor requires 4 parameters. X, y, width and height. This defines the dimensions of our rectangle. Internally the constructor will create the polygon data needed by the polygon collider constructor.

RectangleCollider(x, y, width, height)

This is how it would look:

new RectangleCollider(0, 0, 25, 60)

The rectangle collider exposes four other parameters apart from the ones polygon collider has.

// X Coordinate of our collider
x
// Y Coordinate of our collider
y
// Width of our rectangle
width
// Height of our rectangle
height

AABB Collider

AABB Collider is a completely different type of collider and it doesn’t extend from polygon collider. Basically it’s Phaser’s old body. AABB Collider is used to handle collisions the same way they were handled on Arcade 1. AABB Colliders won’t be affected by rotation as polygon colliders do. This type of collider will yield a much faster collision solving execution as it’s simpler to solve. Unless you need to do some complex polygonal collision testing then I would suggest using AABB Collider.

AABB Collider’s constructor is similar to Rectangle collider:

AABBCollider(x, y, width, height)

You just need to define the dimensions of our bounding box. It also exposes some properties than can be used to access bounding box data.

// X Coordinate of our collider
x
// Y Coordinate of our collider
y
// Width of our bounding box
width
// Height of our bounding box
height

Colliders don’t have logic inside them. They just work as simple abstractions for users to use. Internally all AABB and Polygon data is stored in isolated typed arrays.

What about the body?

Arcade 2 Body is very similar to Arcade 1. It exposes similar properties like velocity, acceleration, bounce, etc. One of the main differences is that it doesn’t contain logic. All logic is handled by the systems. In a same way as colliders work they are just plain old data (POD).

The Body constructor requires three parameters.

Body(x, y, collider)

The x and y parameters are the position the body will be. The position of the body will affect the collider. This means that the collider will be relative to the body position.

The collider parameter is mandatory. If you don’t pass a collider the constructor will throw and exception.

These are the properties exposed by the Body class.

// Body's Immovable Boolean
immovable

// Body's Position Vector
position

// Body's Velocity Vector
velocity

// Body's Acceleration Vector
acceleration

// Body's Gravity Vector
gravity

// Body's Bounce Vector
bounce

// Body's Max Velocity Vector
maxVelocity

// Body's Friction Vector
friction

// Body's Drag Vector
drag

// Body's Rotation Scalar
rotation

// Body's Angular Velocity Scalar
angularVelocity

// Body's Angular Acceleration Scalar
angularAcceleration

// Body's Angular Drag Scalar
angularDrag

// Body's Max Angular Velocity Scalar
maxAngular

// Body's Mass Scalar
mass

image

How to use it

I know that this might look like a lot of information, but the API has been designed to be easy and familiar to use. This means that if you’ve used Phaser’s Arcade Physics you won’t have much trouble using Arcade 2.

Here is a really simple example of how to create a body.

var spriteBody = new Body(
    0,
    0,
    new AABBCollider(-10, -10, 20, 20)
);

What we are doing here is setting out body to the coordinates (0, 0) and creating an AABB collider that’ll be aligned at the center of our body.

The new way of updating and doing all the check for Arcade 2 is done like this:

// Our callback
function onCollide(aID, bID) {
    console.log('Body with ID', aID, 'has collided with body with ID', bID);
}

function update() {
    // This will at some point be handled internally
    // by the game engine in the future.
    UpdatePhysics(game.physicsStep);

    // A similiar API to Phaser Arcade Physics.
    Collide(bodyA, bodyB, onCollide);

    // The same as UpdatePhysics. It'll be handled
    // By the game engine in the future.
    UpdateCollisions();
}

As you can see currently we have to manually call UpdatePhysics and UpdateCollisions. This will probably be moved to an internal routine in the future.

As you can see it’s very simple and similar to what Phasers Arcade API looks like. One of the main differences between Arcade 1 and 2 is that Collide and Overlap don’t return a Boolean. This is because of a design restriction.

Demos

The Lazer Labs site contains all of the current Arcade Physics 2 examples.

You can also see all of the source code, for all of the examples, in the Lazer Dev GitHub repo.

As this implementation is fairly new it would be really useful for us to have your opinion and also help us catching bugs so please go ahead and try it out.

Play and break it so we can fix it :)

The Future

There is a lot of features I would like to see on Arcade 2. Here is a list of things I think would be really useful to have:

  • Circle Collider.
  • Compound Polygon Collider (Useful for levels).
  • More Collision Categories (Circle to Polygon, Circle to Circle, etc).
  • Group Collisions.
  • Some kind of spatial hashing for performance improvement (Quadtree).
  • Parallel execution of tasks (Multithreading).
  • Immediate collision and overlap mode (similar to Arcade 1).
  • (Maybe) Static Collision system (no need to push collision data every frame).