Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.math.collision;

import com.gebauz.bauzoid.graphics.Graphics;
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.Shape;

/** Interface for shape element. */
public abstract class BaseShapeElement
{
        // Constants========================================================================================

        // Embedded Types===================================================================================

        // Fields===========================================================================================
       
        private Shape mOwner = null;
       
        protected Vector2[] mProjectionAxes = null;
        protected Vector2[] mPoints = null;
        protected Vector2[] mUntransformedPoints = null;
        protected Line2[] mLines = null;
        protected Line2[] mUntransformedLines = null;
        protected Line2[] mSweepLines = null;
       
        private Vector2 mIntersectionPoint = new Vector2();
        private Vector2 mContactPoint = new Vector2();
        private CollisionUtil.PenetrationResult penetrationResult = new CollisionUtil.PenetrationResult();
       
        private int mStartFrame = -1;
        private int mEndFrame = -1;

        // Methods==========================================================================================

        public BaseShapeElement(Shape shape, int startFrame, int endFrame)
        {
                mOwner = shape;
                mStartFrame = startFrame;
                mEndFrame = endFrame;
        }
       
        /** Copy shape with new owner. */
        public abstract BaseShapeElement copy(Shape newOwner);
       
        /** Calculate intersection with a group of shape elements. */
        /*public CollisionResult collide(Shape shape)
        {
                return collide(shape, null);
        }*/

       
        /** Calculate intersection with a group of shape elements along movement vector.
         * Returns true if a collision occurs.
         * resultPenetration contains the minimal penetration vector.
         * resultContactPoint contains the contact point.
         */
   
        public boolean collide(Shape shape, Vector2 move, Vector2 resultPenetration, Vector2 resultContactPoint)
        {
                //CollisionResult result = new CollisionResult();
               
                resultPenetration.set(0, 0);
                resultContactPoint.set(0, 0);
               
                boolean isColliding = false;
               
                // move
                float tempX = getOwner().transform.x;
                float tempY = getOwner().transform.y;
               
                if (move != null)
                {
                        getOwner().transform.x += move.x;
                        getOwner().transform.y += move.y;
                }
               
                int numContactPoints = 0;
               
                for (int i = 0; i < shape.getShapeElementCount(); i++)
                {
                        //Line2[] poly1 = getSweepLineSegments(move);
                        Line2[] poly1 = getLineSegments();
                        Vector2[] axes1 = getProjectionAxes();
                        Line2[] poly2 = shape.getShapeElement(i).getLineSegments();
                        Vector2[] axes2 = shape.getShapeElement(i).getProjectionAxes();
                       
                        penetrationResult.reset();                             
                        if (CollisionUtil.calculatePenetration(poly1, poly2, axes1, axes2, penetrationResult))
                        {
                                isColliding = true;
                                resultPenetration.addVector(penetrationResult.penetrationVector);
                               
                                // apply correction
                                getOwner().transform.x += penetrationResult.penetrationVector.x;
                                getOwner().transform.y += penetrationResult.penetrationVector.y;
                               
                                numContactPoints = 1;
                                mContactPoint.setFrom(penetrationResult.contactPoint);
                        }
                }
               
                if (isColliding)
                {                      
                        // get contact point
                        mContactPoint.x /= numContactPoints;
                        mContactPoint.y /= numContactPoints;
                        resultContactPoint.setFrom(mContactPoint);
                }
               
                // restore original position (result penetration vector is going to be applied outside)
                getOwner().transform.x = tempX;
                getOwner().transform.y = tempY;
                       
                return isColliding;
        }
       
        /** Collide with a ray.
         * Only returns a contact point, no penetration vector.
         */

        public boolean collideRayCast(Line2 ray, Vector2 resultContactPoint)
        {
                Line2 lines[] = getUntransformedLineSegments();
               
                float minimumDistanceSqr = Float.MAX_VALUE;
                boolean foundContact = false;

                for (int i = 0; i < lines.length; i++)
                {
                        if (!ray.getSegmentIntersection(lines[i], mIntersectionPoint))
                                continue;
                       
                        float dx = mIntersectionPoint.x - ray.a.x;
                        float dy = mIntersectionPoint.y - ray.a.y;

                        float distanceSqr = dx*dx + dy*dy;
                        if (distanceSqr < minimumDistanceSqr)
                        {

                                minimumDistanceSqr = distanceSqr;
                                resultContactPoint.setFrom(mIntersectionPoint);
                                foundContact = true;
                        }
                }
               
                return foundContact;
        }
       
        /** Check if the shape intersects a circle. */
        public boolean intersectsCircleSqr(float x, float y, float radiusSqr)
        {
                Line2[] poly = getLineSegments();

                //Gdx.app.log("BLA", "--------------");
                //Gdx.app.log("BLA", "p: " + x + ", " + y + " r: " + radiusSqr);
                for (int i = 0; i < poly.length; i++)
                {
                        Line2 l = poly[i];
                       
                        float distanceSqr = l.getClosestSquaredDistanceFrom(x, y);

                        //Gdx.app.log("BLA", "a: " + l.a.x + ", " + l.a.y + " - " + l.b.x + ", " + l.b.y + " d: " + distanceSqr);
                       
                        if (distanceSqr <= radiusSqr)
                                return true;
                }
               
                return false;
        }
       
        public boolean isInFrameRange(int frame)
        {
                int startFrame = mStartFrame;
                int endFrame = mEndFrame;
                if (startFrame == -1)
                        startFrame = 0;
                if (endFrame == -1)
                        endFrame = Integer.MAX_VALUE;
               
                return ((frame >= startFrame) && (frame <= endFrame));
        }
       
        /** Check if the point lies inside the shape element. The point should be specified in the shape's sprite space. */
        public abstract boolean isInside(float x, float y);

        /** Render debug output. */
        public abstract void renderDebug(Graphics graphics, SpriteTransform t);
       
        /** Get a list of untransformed points that make up the polygon. */
        public abstract Vector2[] getUntransformedPoints();
       
        /** Get a list of transformed (with the parent shape's SpriteTransform) points that make up the polygon. */
        public abstract Vector2[] getPoints();
       
        /** Get a list of untransformed line segments that make up the polygon. */
        public abstract Line2[] getUntransformedLineSegments();
       
        /** Get a list of transformed (with the parent shape's SpriteTransform) line segments that make up the polygon. */
        public abstract Line2[] getLineSegments();
       
        /** Get a list of transformed line segments including the swept shape. */
        //public abstract Line2[] getSweepLineSegments(Vector2 move);
       
        /** Get all vectors for all distinct projection axes for separating axis theorem. */
        public abstract Vector2[] getProjectionAxes();
       
        // Getters/Setters==================================================================================
       
        public final void setOwner(Shape shape)
        {
                mOwner = shape;
        }
       
        public final Shape getOwner()
        {
                return mOwner;
        }
       
        public final SpriteTransform getTransform()
        {
                return mOwner.transform;
        }

        public final Vector2 getCenter()
        {
                Vector2 result = new Vector2();
                Vector2[] points = getPoints();
                for (int i = 0; i < points.length; i++)
                {
                        result.addVector(points[i]);
                }
                result.x /= points.length;
                result.y /= points.length;
               
                return result;
        }

       

}