[BS-03] Text Collider

posted

2023-05-13

updated

2023-05-13
[BS-03] Text Collider - Teaser

Adding simplistic Physics


For the step i wanted to add collisions.
The words and letters were already colliding with the wall, so letting them collide with each other seemed like a natural way to progress.

Features


The controls stay the same as for the text spawner, this time though, if two blocks of text collide the change direction and color.

Upcoming


Instead of showing letters we could go for displaying images.

Also state transitioning between a menu and the game itself might be a good idea.

Details


The "physics engine" really is as simplistic as it can get while still hopefully open for later changes.
The velocity handling and collision with the world bounds have moved into the physics engine, with a fixed step size.

The PhysicsEngine does not directly accept Entites from the GameModel.
They first need to be wrapped into a Proxy to be used in any PhysicsEngine.
It keeps the physic body's bounding box, a unique ID and a reference to the proxied Entity.
It is important to remember to add and remove Entities from the physics engine appropriatly, other wise "Ghost"-bodies could produce unwanted effects.

export class CollisionProxy {
    public static next_id = 0;
    public id: number = CollisionProxy.next_id++;

    constructor(
        public outerBox: Rect,
        public reference: CollisionProxiable,
    ) {

    }

    /**
     * A collision has occurred between this entity and another.
     * @param other 
     * @param collision 
     */
    public onCollision(other: CollisionProxy, collision: Collision) {
        if ( !!this.reference.onCollision ) {
            this.reference.onCollision(other, collision);
        }
    }
}

This CollisionProxy is extended for the  currently in use, by the velocity.
And that is all that physics directly interacts with.
On the other hand this also means, that the outerBox and velocity objects should always be synched to the entites posistion values used for rendering. In this case i simply kept the refernce to them in the entity and made sure to only read-access them.

The collision handling itself is just brute force AABB checking for now.
The collisions in the step will also be saved to the PhysicsEngine if some logic would be easier to handle outside of an Entity.

    public checkCollisions() {
        this.collisions = [];
        this.proxies.forEach(proxy => {
            this.proxies.forEach(other => {
                // don't collide with yourself
                if (proxy === other) return;
                // get overlapping rectangle between the two boxes
                const overlap = proxy.outerBox.overlap(other.outerBox);
                // if the overlap is a "real" rectangle, then there is a collision
                if (overlap.bottom > overlap.top && overlap.right > overlap.left) {
                    this.handleCollision(proxy, other, overlap);
                }
            });
        });
    }

If a collision is detected first the physics will be solved by moving the two boxes apart and adjusting the velocity.
After that it will call the collision callback on the two boxes.
    public handleCollision(proxy: AABBCollisionProxy, other: AABBCollisionProxy, overlap: BoundingBox) {
        // create a collision object
        const collision : AABBCollision = {
            overlap: overlap,
            a: proxy,
            b: other,
        }
        // solve the collision on physics side
        this.solveCollision(collision);
        // call the onCollision callback for each box
        proxy.onCollision(other, collision);
        other.onCollision(proxy, collision);    
        // add the collision to the list of collisions
        this.collisions.push(collision);
    }

Overall there are many things, easily optimizable right now, so i will probably come back to this a lot.
Improvement Ideas:

Releases

Comments

captcha