Subversion Repositories AndroidProjects

Rev

Rev 1362 | Rev 1365 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.gebauz.burutaru.game.entities;

import java.util.Vector;

import com.gebauz.bauzoid.graphics.sprite.SpriteTransform;
import com.gebauz.bauzoid.math.Line2;
import com.gebauz.bauzoid.math.Vector2;
import com.gebauz.bauzoid.math.collision.AABoundingBox;
import com.gebauz.bauzoid.math.collision.BaseShapeElement;
import com.gebauz.bauzoid.math.collision.Shape;
import com.gebauz.burutaru.game.GameLogic;
import com.gebauz.burutaru.game.entities.enemies.EnemyInstance;
import com.gebauz.burutaru.game.entities.level.elements.BaseLevelElement;

/** Global collision world that contains different colliders. */
public class CollisionWorld extends Entity
{

        // Constants========================================================================================
       
        public static final int FILTER_LEVEL_ELEMENTS = 1;
        public static final int FILTER_ENEMIES = 2;
       
        public static final int FILTER_ALL = FILTER_LEVEL_ELEMENTS | FILTER_ENEMIES;

        // Embedded Types===================================================================================
       
        public static class CollisionInfo
        {
                public boolean isColliding = false;
               
                public Vector2 penetrationVector = new Vector2();
                public Vector2 contactPoint = new Vector2();
               
                public BaseLevelElement collidingLevelObject = null;
                //public Entity collidingEntity = null;
                public EnemyInstance collidingEnemyInstance = null;
               
                public void reset()
                {
                        isColliding = false;
                        collidingLevelObject = null;
                        collidingEnemyInstance = null;
                }
        }

        public class ColliderInfo
        {
                public int collisionFilter = 0;
               
                public EnemyInstance enemyInstance = null;
                public BaseLevelElement levelElement = null;
                public Shape shape = null;
               
                public ColliderInfo(EnemyInstance enemy, Shape enemyShape)
                {
                        collisionFilter = FILTER_ENEMIES;
                        enemyInstance = enemy;
                        shape = enemyShape;
                }
               
                public ColliderInfo(BaseLevelElement levelObject, Shape objShape)
                {
                        collisionFilter = FILTER_LEVEL_ELEMENTS;
                        levelElement = levelObject;
                        shape = objShape;
                }
               
                public final boolean contains(int filter)
                {
                        return ((collisionFilter & filter) != 0);
                }
               
                public final boolean isColliderAlive()
                {
                        if (contains(FILTER_LEVEL_ELEMENTS))
                                return (levelElement.isAlive());
                       
                        if (contains(FILTER_ENEMIES))
                                return (enemyInstance.isAlive());
                       
                        return false;
                }
        }

        // Fields===========================================================================================
       
        /** Collection of passive colliders. */

        private Vector<ColliderInfo> mColliders = new Vector<ColliderInfo>();
       
        /** Temp variables. */
        private Vector2 mResultPenetration = new Vector2();
        private Vector2 mResultContactPoint = new Vector2();
        private AABoundingBox mTempBoundingBox = new AABoundingBox();
        private Line2 mRay = new Line2();
        private Vector2 p1 = new Vector2();
        private Vector2 p2 = new Vector2();

        // Methods==========================================================================================
       
        public CollisionWorld(GameLogic gameLogic)
        {
                super(gameLogic);
        }
       
        @Override
        public void initAsync()
        {
        }

        @Override
        public void init()
        {
        }

        @Override
        public void exit()
        {
        }

        @Override
        public void update(float deltaTime)
        {
        }

        @Override
        public void render()
        {

        }
       
        /** Add Reference to a passive collider. */
        public void addPassiveCollider(BaseLevelElement obj, Shape shape)
        {
                //mPassiveColliders.add(new PassiveColliderInfo(obj, shape));
               
                mColliders.add(new ColliderInfo(obj, shape));
        }
       
        public void addEnemyCollider(EnemyInstance obj, Shape shape)
        {
                //mEnemyColliders.add(new EnemyColliderInfo(obj, shape));
               
                mColliders.add(new ColliderInfo(obj, shape));
        }
       
        /** Check for collision of shape with passive colliders, return contact point and minimal translation vector.
         * Suitable for ship<->environment collisions.
         */

        public boolean checkCollisionSat(int filter, Shape shape, Vector2 move, CollisionInfo result)
        {
                result.reset();
               
                // Check broadphase collision
                shape.transform.x += move.x;
                shape.transform.y += move.y;
                AABoundingBox box1 = shape.getTransformedBoundingBox();
               
                // Check collision between object and level objects
                for (int i = 0; i < mColliders.size(); i++)
                {
                        ColliderInfo info = mColliders.get(i);
                       
                        if (!info.contains(filter))
                                continue;

                        if (!info.isColliderAlive())
                                continue;
                       
                        AABoundingBox box2 = info.shape.getTransformedBoundingBox();
                        if (!box1.intersetcs(box2))
                                continue;
                       
                        if (shape.getShapeElement(0).collide(info.shape, move, mResultPenetration, mResultContactPoint))
                        {
                                result.isColliding = true;
                                result.penetrationVector.setFrom(mResultPenetration);
                               
                                if (info.contains(FILTER_LEVEL_ELEMENTS))
                                        result.collidingLevelObject = info.levelElement;
                                else if (info.contains(FILTER_ENEMIES))
                                        result.collidingEnemyInstance = info.enemyInstance;
                               
                                if (mResultContactPoint != null)
                                        result.contactPoint.setFrom(mResultContactPoint);
                        }
                }
               
                shape.transform.x -= move.x;
                shape.transform.y -= move.y;
               
                return result.isColliding;
        }
       
        /** Check for collision by raycasting and return a contact point only (no minimal translation vector).
         * Only suitable for thin objects where raycasting suffices as a collision detection scheme.
         * Suitable for fast, thin projectile <-> environment collisions.
         */

        //public CollisionInfo collideRaycast(int filter, Vector2 pos, Vector2 velocity)
        public boolean checkCollisionRaycast(int filter, Vector2 rayPos, Vector2 rayDir, CollisionInfo result)
        {
                mTempBoundingBox.setFromRay(rayPos, rayDir);
               
                float minimumDistanceSqr = Float.MAX_VALUE;
               
                result.isColliding = false;

                // Check raycasts between object and level objects
                for (int i = 0; i < mColliders.size(); i++)
                {
                        ColliderInfo info = mColliders.get(i);
                       
                        if (!info.contains(filter))
                                continue;
                       
                        if (!info.isColliderAlive())
                                continue;
                       
                        AABoundingBox box2 = info.shape.getTransformedBoundingBox();
                        if (!mTempBoundingBox.intersetcs(box2))
                                continue;
                       
                        // transform ray into the shape's space
                        SpriteTransform t = info.shape.transform;
                       
                        t.worldToSprite(rayPos.x, rayPos.y, p1);
                        t.worldToSprite(rayPos.x + rayDir.x, rayPos.y + rayDir.y, p2);
                       
                        mRay.set(p1, p2);
                       
                        for (int j = 0; j < info.shape.getShapeElementCount(); j++)
                        {
                                BaseShapeElement e = info.shape.getShapeElement(j);
                               
                                if (e.collideRayCast(mRay, mResultContactPoint))
                                {
                                        float dx = mResultContactPoint.x - p1.x;
                                        float dy = mResultContactPoint.y - p1.y;
                                        float distanceSqr = dx*dx+dy*dy;
                                       
                                        if (distanceSqr < minimumDistanceSqr)
                                        {
                                                result.isColliding = true;
                                                minimumDistanceSqr = distanceSqr;
                                               
                                                t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y, result.contactPoint);
                                               
                                                if (info.contains(FILTER_ENEMIES))
                                                        result.collidingEnemyInstance = info.enemyInstance;
                                                else if (info.contains(FILTER_LEVEL_ELEMENTS))
                                                        result.collidingLevelObject = info.levelElement;
                                        }
                                }
                        }
                }      
                return result.isColliding;
        }
       
       
        public boolean checkCollisionPoint(int filter, float px, float py, float radius, CollisionInfo result)
        {
                result.reset();
               
                float radiusSqr = radius*radius;
               
                for (int i = 0; i < mColliders.size(); i++)
                {
                        ColliderInfo info = mColliders.get(i);
                       
                        if (!info.contains(filter))
                                continue;
                       
                        if (!info.isColliderAlive())
                                continue;
                       
                        AABoundingBox box = info.shape.getTransformedBoundingBox();
                        if (!box.isInside(px, py))
                                continue;
                       
                        // transform point into shape's space
                        //SpriteTransform t = info.shape.transform;
                        //t.worldToSprite(px, py, p1);
                       
                        for (int j = 0; j < info.shape.getShapeElementCount(); j++)
                        {
                                BaseShapeElement e = info.shape.getShapeElement(j);
                               
                                if (e.intersectsCircleSqr(px, py, 5))
                                //if (e.isInside(p1.x, p1.y))
                                {
                                        result.isColliding = true;
                                       
                                        if (info.contains(FILTER_ENEMIES))
                                                result.collidingEnemyInstance = info.enemyInstance;
                                        else if (info.contains(FILTER_LEVEL_ELEMENTS))
                                                result.collidingLevelObject = info.levelElement;
                                       
                                        /*float dx = mResultContactPoint.x - p1.x;
                                        float dy = mResultContactPoint.y - p1.y;
                                        float distanceSqr = dx*dx+dy*dy;
                                       
                                        if (distanceSqr < minimumDistanceSqr)
                                        {
                                                result.isColliding = true;
                                                minimumDistanceSqr = distanceSqr;
                                               
                                                t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y, result.contactPoint);
                                               
                                                if (info.contains(FILTER_ENEMIES))
                                                        result.collidingEnemyInstance = info.enemyInstance;
                                                else if (info.contains(FILTER_LEVEL_ELEMENTS))
                                                        result.collidingLevelObject = info.levelElement;
                                        }*/

                                }
                        }
                       
                }
               
                return result.isColliding;
        }
       
       
        // Getters/Setters==================================================================================

}