5
\$\begingroup\$

This code is an excerpt from an infinite platformer I'm working on for fun. It belongs to the class GameObject from which every object i.e platforms, player, collectables extends and it primarily handles collision and movement.

On each game tick, the collision function is called. It grabs a list of all the GameObjects from its parent class (all GameObjects share a common parent). It then loops through each object, and if they are at similar heights it performs a collision check.

Each GameObject can check for collisions to the right, left and down (in this game it is impossible to hit something above you). It does this by defining collision vertices, which are separate x, y coordinates for each direction that define where on the object it should fire a ray from. For example, the variable m_downCollisionVertices may store two points that are positioned at the player's feet, so when the collision check runs, it fires a ray downwards from both of those points to see if it intersects with the GameObject it's currently checking against.

If the ray collides with the GameObject, it determines whether or not on the next frame they will have moved far enough to intersect and if so handles this collision.

Concerns

You will notice that the down, left and right collision sections in my code are nearly identical, and I'm running a separate for loop for each direction that I test. To me, this seems excessive however this is as far as I've been able to take it.

Notes

Vec2 is my own standard math vector class.

GameObject.as

protected var m_collisionShapeParented:Vector.<Vec2>;

protected var m_rightCollisionVertices:Vector.<Vec2> = new Vector.<Vec2>;
protected var m_leftCollisionVertices:Vector.<Vec2> = new Vector.<Vec2>;
protected var m_downCollisionVertices:Vector.<Vec2> = new Vector.<Vec2>;
protected var m_numRightCollisionVertices:int = 0;
protected var m_numLeftCollisionVertices:int = 0;
protected var m_numDownCollisionVertices:int = 0;

protected var m_collisionRayLength:int = 40;

protected var m_pos:Vec2 = new Vec2(0, 0);
protected var m_vel:Vec2 = new Vec2(0, 0);

protected var m_simpleCollisions:Boolean = false;

protected var m_onGround:Boolean = false;
protected var m_rightCollisionObject:GameObject;
protected var m_leftCollisionObject:GameObject;
protected var m_downCollisionObject:GameObject;

protected const DIR_LEFT:Vec2 = new Vec2( -1, 0);
protected const DIR_RIGHT:Vec2 = new Vec2( 1, 0);
protected const DIR_DOWN:Vec2 = new Vec2( 0, 1);
protected const DIR_UP:Vec2 = new Vec2( 0, -1);

protected const COLLISION_TOLERANCE:Number = 2;
protected const COLLISION_CHECK_RANGE:Number = 50;

protected function collision(dt:Number):void
{   
    // Retrieve all active game objects
    var gameObjects:Vector.<GameObject> = m_parent.m_objects;
    var numGameObjects:int = gameObjects.length;

    // Loop through all game objects
    for (var i:int = 0; i < numGameObjects; i++)
    {   
        // If game objects are at similar heights, check for collisions
        if (Math.abs(gameObjects[i].position.y - m_pos.y) < COLLISION_CHECK_RANGE)
        {   
            if (!gameObjects[i].m_simpleCollisions)
            {                           
                // Stores whether or not a collision was found, the point of collision,
                // and the length of the ray when the collision was found
                var collisionData:CollisionData;

                // The combined distance that this GameObject,
                // and the GameObject being checked against will move this frame
                var combinedMoveDistance:Vec2 = m_vel.scale(dt).subtract(gameObjects[i].m_vel.scale(dt));

                /*** Down Collisions ***/
                // Reset m_onGround to false ready to start the next check
                m_onGround = false;
                for (var k:int = 0; k < m_numDownCollisionVertices; k++)
                {   
                    // Perform the rayCast collision check
                    collisionData = Collision.rayCollision(m_downCollisionVertices[k].sum(m_pos), DIR_DOWN,
                                                            m_collisionRayLength, gameObjects[i].m_collisionShapeParented);

                    if (collisionData.foundCollision)
                    {   
                        // Check if the GameObjects will move far enough to intersect                           
                        if (collisionData.rayLength <= combinedMoveDistance.y || collisionData.rayLength <= COLLISION_TOLERANCE)
                        {   
                            m_downCollisionObject = gameObjects[i];
                            m_onGround = true;

                            // Move object down to where the collision was detected
                            m_pos.y += collisionData.rayLength-1;
                            position = m_pos;

                            // Remove any Y velocity
                            m_vel.y = 0;

                            m_downCollisionObject.collided(this, DIR_DOWN);
                        }
                    }                           
                }

                /*** Right Collisions ***/
                for (var m:int = 0; m < m_numRightCollisionVertices; m++)
                {   
                    // Check if the GameObjects will move far enough to intersect                       
                    collisionData = Collision.rayCollision(m_rightCollisionVertices[m].sum(m_pos), DIR_RIGHT,
                                                            m_collisionRayLength, gameObjects[i].m_collisionShapeParented);

                    if (collisionData.foundCollision)
                    {                               
                        if (collisionData.rayLength < combinedMoveDistance.x || collisionData.rayLength <= COLLISION_TOLERANCE)
                        {
                            m_rightCollisionObject = gameObjects[i];

                            // Move this GameObject right to where the collision was detected
                            m_pos.x += collisionData.rayLength;
                            position = m_pos;

                            // Prevent this GameObject from moving to the right
                            if (m_vel.x > 0)
                            {
                                m_vel.x = 0;
                            }

                            m_rightCollisionObject.collided(this, DIR_RIGHT);
                        }
                    }
                }

                /*** Left Collisions ***/
                for (var n:int = 0; n < m_numLeftCollisionVertices; n++)
                {                           
                    collisionData = Collision.rayCollision(m_leftCollisionVertices[n].sum(m_pos), DIR_LEFT,
                                                            m_collisionRayLength, gameObjects[i].m_collisionShapeParented);

                    if (collisionData.foundCollision)
                    {   
                        // Check if the GameObjects will move far enough to intersect                           
                        if (collisionData.rayLength < combinedMoveDistance.x || collisionData.rayLength < COLLISION_TOLERANCE)
                        {
                            m_leftCollisionObject = gameObjects[i];

                            // Move this GameObject left to where the collision was detected
                            m_pos.x -= collisionData.rayLength;
                            position = m_pos;

                            // Prevent this GameObject from moving to the left
                            if (m_vel.x < 0)
                            {
                                m_vel.x = 0;
                            }

                            m_leftCollisionObject.collided(this, DIR_LEFT);
                        }
                    }   
                }
            }
            else
            {
                // simple bounding box collision
            }
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.