Physics

The engine provides basic physics simulations by means of the Body Component and collisions through various classes of Colliders.

# Body

A Body is a Component that attaches to an Entity. It has basic properties like mass, friction, bounciness, maximum speed and maximum velocity, etc. A BodySpec determines how to initialize these properties when instantiating a Body:

BodyROMSpec SomeActorBodySpec =
{
    // Component
    {
        // Allocator
        __TYPE(Body),

        // Component type
        kPhysicsComponent
    },

    // Create body
    true,

    // Mass
    __F_TO_FIXED(0.5f),

    // Friction
    __F_TO_FIXED(0.1f),

    // Bounciness
    __F_TO_FIXED(0),

    // Maximum velocity
    {__I_TO_FIXED(0), __I_TO_FIXED(0), __I_TO_FIXED(0)},

    // Maximum speed
    __F_TO_FIXED(3),

    // Axises on which the body is subject to gravity
    __NO_AXIS,

    // Axises around which to rotate the owner when syncronizing with body
    __NO_AXIS
    };

An Entity with a Body attached to it will react to forces applied to it:

    Vector3D force =
    {
        Body::getMass(SomeActor::getBody(actor)), 0, 0

    };

    // If the object has a collider attached to it, the last argument
    // forces to check if the movement in the force's direction won't
    // result immediately in a collision
    Actor::applyForce(actor, &force, true);

# Collider

A Collider is a Component that attaches to an Entity too, and is capable of sensing collisions with other Colliders and informing its owner about these events.

The engine provides a few kinds of Collider: Balls, Boxes, LineFields.

The typical ColliderSpec looks like the following:

ColliderROMSpec SomeActorColliderSpec =
{
    // Component
    {
        // Allocator
        __TYPE(Box),

        // Component type
        kColliderComponent
    },

    // Size (x, y, z)
    {16, 38, 24},

    // Displacement (x, y, z, p)
    {0, 1, 0, 0},

    // Rotation (x, y, z)
    {0, 0, 0},

    // Scale (x, y, z)
    {0, 0, 0},

    // If true this collider checks for collisions against other colliders
    true,

    // Layers in which I live
    kLayerActor,

    // Layers to ignore when checking for collisions
    ~(kLayerSolid | kLayerDangers),
};

In order to reduce the number of collision checks as much as possible, the Collider can be configured to be passive: it doesn’t check for collisions itself, but others can still check for collisions against it. Another property used to improve performance is the layers in which a Collider logically exists. This, in conjunction with the property that defines layers to ignore when checking for collisions, helps to reduce the number of tests per game cycle. For example, A Particle might need to bounce when colliding with the floor, but it doesn’t need to test if it collides with an item; in this case, the item’s Collider may be set to live in a collider layer that the Particle’s collider ignores.

Besides memory and performance, there are no other limitations with regards to how many Colliders can be added to the same Entity.

Collision are processed by overriding the following Entity’s methods:

    /// Process a newly detected collision by one of the component colliders.
    /// @param collisionInformation: Information struct about the collision to resolve
    /// @return True if the collider must keep track of the collision to detect if it persists and when it ends; false otherwise
    virtual bool collisionStarts(const CollisionInformation* collisionInformation);

    /// Process a going on collision detected by one of the component colliders.
    /// @param collisionInformation: Information struct about the collision to resolve
    virtual void collisionPersists(const CollisionInformation* collisionInformation);

    /// Process when a previously detected collision by one of the component colliders stops.
    /// @param collisionInformation: Information struct about the collision to resolve
    virtual void collisionEnds(const CollisionInformation* collisionInformation);

The CollisionInformation struct holds information about the colliding Entity, the collision vector, and the Colliders involved in the collision event:

bool SomeActor::collisionStarts(const CollisionInformation* collisionInformation __attribute__ ((unused)))
{
    Entity collidingEntity = Collider::getOwner(collisionInformation->otherCollider);

    if(!isDeleted(collidingEntity))
    {
        switch(Entity::getInGameType(collidingEntity))
        {
            case kTypeSomeEntityType:
                {
                    SomeActor::sendMessageTo
                    (
                        0, ListenerObject::safeCast(this), ListenerObject::safeCast(collidingEntity),
                        kMessageTouchedBySomeActor, NULL
                    );
                }
                break;
        }
    }

    return false;
}