Subversion Repositories AndroidProjects

Rev

Rev 1287 | Rev 1364 | 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 PassiveColliderInfo
        {
                public BaseLevelElement levelObject = null;
                public Shape shape = null;
               
                public PassiveColliderInfo(BaseLevelElement obj, Shape objShape)
                {
                        levelObject = obj;
                        shape = objShape;                      
                }
        }
       
        public class EnemyColliderInfo
        {
                public BaseEnemy.Instance enemyInstance = null;
                public Shape shape = null;
               
                public EnemyColliderInfo(BaseEnemy.Instance obj, Shape objShape)
                {
                        enemyInstance = obj;
                        shape = objShape;
                }
        }
        */

        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<PassiveColliderInfo> mPassiveColliders = new Vector<PassiveColliderInfo>();
       
        private Vector<EnemyColliderInfo> mEnemyColliders = new Vector<EnemyColliderInfo>();*/

       
        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.levelObject.isAlive())
                                continue;*/

                        if (!info.isColliderAlive())
                                continue;
                       
                        AABoundingBox box2 = info.shape.getTransformedBoundingBox();
                        if (!box1.intersetcs(box2))
                                continue;
                       
                        // perform collision detection between actor's convex hull and shape
                        //CollisionResult cr = shape.getConvexHull().collide(info.collider.getShape(), move);
                        //CollisionResult cr = shape.getShapeElement(0).collide(info.shape, move);
                       
                        //if (cr.isColliding)
                        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)
        {
                //CollisionInfo result = new CollisionInfo();
               
                // Check broadphase collision
                //AABoundingBox box1 = AABoundingBox.fromRay(rayPos, rayDir);
                mTempBoundingBox.setFromRay(rayPos, rayDir);
               
                float minimumDistanceSqr = Float.MAX_VALUE;
               
                result.isColliding = false;

                // Check raycasts between object and level objects
                //for (int i = 0; i < mPassiveColliders.size(); i++)
                for (int i = 0; i < mColliders.size(); i++)
                {
                        ColliderInfo info = mColliders.get(i);
                        //PassiveColliderInfo info = mPassiveColliders.get(i);
                       
                        if (!info.contains(filter))
                                continue;
                       
                        if (!info.isColliderAlive())
                                continue;
                        /*if (!info.levelObject.isAlive())
                                continue;*/

                       
                        AABoundingBox box2 = info.shape.getTransformedBoundingBox();
                        if (!mTempBoundingBox.intersetcs(box2))
                                continue;
                       
                        // transform ray into the shape's space
                        SpriteTransform t = info.shape.transform;
                       
                        /*Vector2 p1 = t.worldToSprite(rayPos.x, rayPos.y);
                        Vector2 p2 = t.worldToSprite(rayPos.x + rayDir.x, rayPos.y + rayDir.y);*/

                       
                        t.worldToSprite(rayPos.x, rayPos.y, p1);
                        t.worldToSprite(rayPos.x + rayDir.x, rayPos.y + rayDir.y, p2);
                       
                        //Line2 ray = new Line2(p1, p2);
                        mRay.set(p1, p2);
                       
                        for (int j = 0; j < info.shape.getShapeElementCount(); j++)
                        {
                                BaseShapeElement e = info.shape.getShapeElement(j);
                               
                                //CollisionResult cr = e.collideRayCast(ray);
                               
                                //if (cr.isColliding)
                                if (e.collideRayCast(mRay, mResultContactPoint))
                                {
                                        //Vector2 posToContact = new Vector2(mResultContactPoint.x - p1.x, mResultContactPoint.y - p1.y);
                                        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;
                                               
                                                //Gdx.app.log("BLA", "contact: " + result.contactPoint.x + ", " + result.contactPoint.y + " - " + t.x + ", " + t.y);
                                               
                                                //result.contactPoint = t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y);
                                                t.spriteToWorld(mResultContactPoint.x, mResultContactPoint.y, result.contactPoint);
                                               
                                                //Gdx.app.log("BLA", "result contact: " + result.contactPoint.x + ", " + result.contactPoint.y);
                                               
                                                if (info.contains(FILTER_ENEMIES))
                                                        result.collidingEnemyInstance = info.enemyInstance;
                                                else if (info.contains(FILTER_LEVEL_ELEMENTS))
                                                        result.collidingLevelObject = info.levelElement;
                                                //result.collidingLevelObject = info.levelObject;
                                        }
                                }
                        }
                }      
               
                /*if (result.isColliding)
                {
                        Gdx.app.log("BLA", "---> result contact: " + result.contactPoint.x + ", " + result.contactPoint.y);
                }
                */

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

}