Package engine.utility

Source Code of engine.utility.PhysicsAnj$Collision$Intersect

package engine.utility;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import engine.geometry.Polygon;
import engine.geometry.Vector;
import game.terrain.Block;

/* Slides in the closest free direction
* TODO: Finish coding and debugging
*/
public class PhysicsAnj implements PhysicsMode {
    public static class Collision {
        ArrayList<Intersect> intersects;
        boolean wrap = false;
       
        static class Intersect {
            double angle;
            Vector vect;
           
            Intersect (double angle, Vector vect) {
                this.angle = angle;
                this.vect = vect;
            }
        }
       
        static class MergeableIntersect implements Comparable<MergeableIntersect> {
            Intersect intersect;
            CollisionIter iter;
           
            public MergeableIntersect(Intersect intersect, CollisionIter iter) {
                this.intersect = intersect;
                this.iter = iter;
            }

            @Override
            public int compareTo(MergeableIntersect other) {
                return Double.compare(intersect.angle, other.intersect.angle);
            }
        }
       
        static class CollisionIter {
            Iterator<Intersect> iter;
            boolean state;
           
            CollisionIter (Collision collision) {
                iter = collision.intersects.iterator();
                state = collision.wrap;
            }
           
            boolean next () {
                iter.next();
                state = !state;
                return state;
            }
        }
       
        static Collision merge (ArrayList<Collision> collisions, boolean union) {
            ArrayList<MergeableIntersect> combinedIntersects = new ArrayList<MergeableIntersect>();
           
            int collidingCount = 0;
            for (Collision collision : collisions) {
                CollisionIter collisionIter = new CollisionIter(collision);
                if (collision.wrap) {
                    collidingCount++;
                }
               
                for (Intersect intersect : collision.intersects) {
                    combinedIntersects.add(new MergeableIntersect(intersect, collisionIter));
                }
            }
           
            Collections.sort(combinedIntersects);
           
            boolean combinedState;
            boolean previousCombinedState;
            if (union) {
                combinedState = collidingCount>0;
            } else {
                combinedState = collidingCount==collisions.size();
            }
           
            Collision result = new Collision(combinedState);
           
            for (MergeableIntersect intersect : combinedIntersects) {
                boolean state = intersect.iter.next();
                if (state) {
                    collidingCount++;
                } else {
                    collidingCount--;
                }
                previousCombinedState = combinedState;
                if (union) {
                    combinedState = collidingCount>0;
                } else {
                    combinedState = collidingCount==collisions.size();
                }
                if (combinedState != previousCombinedState) {
                    result.intersects.add(intersect.intersect);
                }
            }
           
            return result;
        }
       
        /* Closest free location to vector */
        public Vector closest (Vector v) {
            // TODO
            return v;
        }
       
        /* A monotonic function of vector angle
         * Vector is assumed to be normalised
         * Output in range -2 to +2
         */
        private static double map (Vector v) {
            if (v.getX() > 0) {
                return 1 - v.getY();
            } else {
                return v.getY() - 1;
            }
        }
       
        /* Holds a collision range
         * Range is clockwise from start to end
         * When angle between vectors is small, reflexAngle is used to determine direction
         * Vectors are assumed to be normalised
         */
        public Collision (Vector start, Vector end, boolean reflexAngle) {
            double a = map(start); // start mapped to range 'a' = -2 to 2
            double b = map(end); // end mapped to range 'b' = -2 to +2
           
            if (a <= b) {
                intersects.add(new Intersect(a, start));
                intersects.add(new Intersect(b, end));
            } else {
                intersects.add(new Intersect(b, end));
                intersects.add(new Intersect(a, start));
            }
           
            if (b+1 < a || (reflexAngle && b < a+1)) {
                /* either:
                 *  - end angle is definitely smaller than start angle
                 *  - angles are close and reflex
                 * which means they must have wrapped
                 */
                wrap = true;
            }
        }
 
        /* Holds a collision range
         * Complete collision if fill is true, else empty collision
         */
        public Collision (boolean fill) {
            wrap = fill;
        }
    }

    /* Circular collision with single axis */
    public static Collision axisCollision (Vector normal, double distance, Vector velocity) {
        double cSqr = velocity.magnitudeSquared(); // TODO: cache this for entire shape
        double bSqr = distance*distance;
        double aSqr = cSqr - bSqr;
       
        if (aSqr <= 0) {
            // no intersect with axis
            // complete collision if shape has crossed axis, else empty collision
            return new Collision(distance < 0);
        }
       
        double c = Math.sqrt(cSqr); // TODO: cache this for entire shape
        double b = distance;
        double a = Math.sqrt(aSqr);

        // find first intersect with axis anti-clockwise of normal
        Vector start = new Vector (-b*normal.getX() + a*normal.getY(), -b*normal.getY() - a*normal.getX());
        // find first intersect with axis clockwise of normal
        Vector end = new Vector (-b*normal.getX() - a*normal.getY(), -b*normal.getY() + a*normal.getX());
       
        // normalise
        start.divide(c);
        end.divide(c);
       
        return new Collision(start, end, distance < 0);
    }
   
    /* Collision with single shape */
    public static Collision shapeCollision (Polygon s, Polygon d, Vector velocity) {
        Vector normal = new Vector(); // used to temporarily store normals in loop
        ArrayList<Collision> collisions = new ArrayList<Collision>();
       
        // SAT (Separating Axis Theorem) axes for dynamic shape
        int dSize = d.getSize();
        for (int i=0; i<dSize; i++) {
            d.getNormal(i, normal);
            double distance = Physics.minProjection(s, normal) - Physics.maxProjection(d, normal);
            collisions.add(axisCollision (normal, distance, velocity));
        }
       
        // SAT axes for static shape
        int sSize = s.getSize();
        for (int i=0; i<sSize; i++) {
            s.getNormal(i, normal);
            normal.flip();
            double distance = Physics.minProjection(s, normal) - Physics.maxProjection(d, normal);
            collisions.add(axisCollision (normal, distance, velocity));
        }
       
        return Collision.merge(collisions, false); // collision if overlapping all axes
    }
   
    /* Collision with everything */
    public static Collision allCollision (Block[][] blocks, Polygon position, Vector velocity) {
        ArrayList<Collision> collisions = new ArrayList<Collision>();
       
        for (Block[] row : blocks) {
            for (Block block : row) {
                collisions.add(shapeCollision(block.getPolygon(), position, velocity));
            }
        }
       
        return Collision.merge(collisions, true); // collision if overlapping any shapes
    }
   
    @Override
    public Vector move(Block[][] blocks, Polygon position, Vector velocity) {
        // TODO
        return null;
    }
}
TOP

Related Classes of engine.utility.PhysicsAnj$Collision$Intersect

TOP
Copyright © 2015 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.