Package engine.utility

Source Code of engine.utility.PhysicsDan$Collision

package engine.utility;

import java.util.LinkedList;
import java.util.List;

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

public class PhysicsDan implements PhysicsMode {
    public static class Collision {
        double time;
        Vector mostClockwise;
        Vector mostAntiClockwise;

        public Collision(double time, Vector vector1, Vector vector2) {
            this.time = time;
            if (vector1.cross(vector2) > 0) {
                // Vector2 is more clockwise
                mostClockwise = vector2;
                mostAntiClockwise = vector1;
            } else {
                mostClockwise = vector1;
                mostAntiClockwise = vector2;
            }
        }

        public void union(Collision other) {
            if (mostClockwise.cross(other.mostClockwise) > 0) {
                // other more clockwise
                mostClockwise = other.mostClockwise;
            }
            if (mostAntiClockwise.cross(other.mostAntiClockwise) < 0) {
                // other more anti-clockwise
                mostAntiClockwise = other.mostAntiClockwise;
            }
        }

        public void intersection(Collision other) {
            if (mostClockwise.cross(other.mostClockwise) < 0) {
                // other's less clockwise
                mostClockwise = other.mostClockwise;
            }
            if (mostAntiClockwise.cross(other.mostAntiClockwise) > 0) {
                // other's less anti-clockwise
                mostAntiClockwise = other.mostAntiClockwise;
            }
        }

        public Vector getBestNormal(Vector velocity) {
            if (mostClockwise.dot(velocity) > mostAntiClockwise.dot(velocity)) {
                return mostClockwise;
            } else {
                return mostAntiClockwise;
            }
        }
    }

    public Collision getCollision(Polygon relStatic, Polygon relDynamic, Vector relVelocity) {
        Vector backVelocity = new Vector(relVelocity).flip().normalise();

        List<Collision> frontFaces = new LinkedList<Collision>();
        List<Collision> backFaces = new LinkedList<Collision>();
        List<Collision> zeroFaces = new LinkedList<Collision>();

        Vector n = new Vector();
        final int size1 = relStatic.getSize();
        for (int i = 0; i < size1; i++) {
            n = relStatic.getNormal(i);

            double nDistance = relStatic.getMaxProjection(i) - Physics.minProjection(relDynamic, n);
            double nVelocity = relVelocity.dot(n);
            double nTime = nDistance / nVelocity;

            if (Rough.equal(nDistance, 0) && Rough.equal(nVelocity, 0)) {
                // Sliding along this face
                zeroFaces.add(new Collision(Double.NaN, new Vector(n), backVelocity));
            } else if (Double.compare(nVelocity, 0) < 0) { // -0.0 and below
                // This is a front face
                frontFaces.add(new Collision(nTime, new Vector(n), backVelocity));
            } else if (Double.compare(nVelocity, 0) >= 0) { // +0.0 and above
                // This is a back face
                backFaces.add(new Collision(nTime, new Vector(n), backVelocity));
            }
        }

        final int size2 = relDynamic.getSize();
        for (int i = 0; i < size2; i++) {
            n = relDynamic.getNormal(i);

            double nDistance = relDynamic.getMaxProjection(i) - Physics.minProjection(relStatic, n);
            n.flip();
            double nVelocity = relVelocity.dot(n);
            double nTime = nDistance / nVelocity;

            if (Rough.equal(nDistance, 0) && Rough.equal(nVelocity, 0)) {
                // Sliding along this face
                zeroFaces.add(new Collision(Double.NaN, new Vector(n), backVelocity));
            } else if (Double.compare(nVelocity, 0) < 0) { // -0.0 and below
                // This is a front face
                frontFaces.add(new Collision(nTime, new Vector(n), backVelocity));
            } else if (Double.compare(nVelocity, 0) >= 0) { // +0.0 and above
                // This is a back face
                backFaces.add(new Collision(nTime, new Vector(n), backVelocity));
            }
        }

        // Find the last entry normal
        double lastEntry = Double.NEGATIVE_INFINITY;
        for (Collision c : frontFaces) {
            if (c.time > lastEntry) {
                lastEntry = c.time;
            }
        }

        // Find the first exit normal
        double firstExit = Double.POSITIVE_INFINITY;
        for (Collision c : backFaces) {
            if (c.time < firstExit) {
                firstExit = c.time;
            }
        }

        if (Rough.less(firstExit, lastEntry)) {
            // Exited before entered => NO collision
            return null;
        } else if (Rough.greater(firstExit, lastEntry)) {
            // Entered before exited => COLLISION
            Collision result = new Collision(lastEntry, backVelocity, backVelocity);

            for (Collision c : frontFaces) {
                if (Rough.equal(c.time, lastEntry)) {
                    result.union(c);
                    // TODO: maybe set lastEntry to the least of these times???
                }
            }

            for (Collision c : zeroFaces) {
                result.union(c);
            }

            if (Rough.equal(result.getBestNormal(relVelocity).dot(relVelocity), 0)) {
                // Just sliding???
                // TODO: work this out...
                return null;
            }
            // All done!
            return result;
        } else {
            // firstExit ~= lastEntry
            // => Near miss???
            // TODO: work this out...
            // We want to make sure we don't scrape on blocks below a slope
            return null;
        }
    }

    @Override
    public Vector move(Block[][] blocks, Polygon position, Vector velocity) {
        double timeToGo = 1;
        for (int count = 0; count < 2; count++) {
            // Get the swept area
            double x1 = position.getMinX();
            double y1 = position.getMinY();
            double x2 = position.getMaxX();
            double y2 = position.getMaxY();
            int r1 = (int) Math.ceil((Math.min(y1, y1 + velocity.getY())) / Block.HEIGHT) - 1;
            int r2 = (int) Math.floor((Math.max(y2, y2 + velocity.getY())) / Block.HEIGHT) + 1;
            int c1 = (int) Math.ceil((Math.min(x1, x1 + velocity.getX())) / Block.WIDTH) - 1;
            int c2 = (int) Math.floor((Math.max(x2, x2 + velocity.getX())) / Block.WIDTH) + 1;

            if (r1 < 0) {
                r1 = 0;
            } else if (r1 > blocks.length) {
                r1 = blocks.length;
            }
            if (r2 < 0) {
                r2 = 0;
            } else if (r2 > blocks.length) {
                r2 = blocks.length;
            }
            if (c1 < 0) {
                c1 = 0;
            } else if (c1 > blocks[0].length) {
                c1 = blocks.length;
            }
            if (c2 < 0) {
                c2 = 0;
            } else if (c2 > blocks[0].length) {
                c2 = blocks.length;
            }

            // Get list of collisions with all blocks
            List<Collision> collisions = new LinkedList<Collision>();
            for (int r = r1; r < r2; r++) {
                for (int c = c1; c < c2; c++) {
                    if (blocks[r][c].getPolygon() != null) {
                        Collision collision = getCollision(blocks[r][c].getPolygon(), position, velocity);
                        if (collision != null && Rough.lessEqual(0, collision.time)
                                && Rough.lessEqual(collision.time, timeToGo)) {
                            collisions.add(collision);
                        }
                    }
                }
            }

            // Default collision
            Vector vel = new Vector(velocity).normalise();
            Vector velNorm = new Vector(vel).normal();
            Vector velAnti = new Vector(vel).antiNormal();
            Collision result = new Collision(Double.POSITIVE_INFINITY, velNorm, velAnti);

            // Find earliest collision
            for (Collision c : collisions) {
                if (c.time < result.time) {
                    result = c;
                }
            }

            // Find all collisions which happened at that time
            for (Collision c : collisions) {
                if (Rough.equal(c.time, result.time)) {
                    result.intersection(c);
                }
            }

            // Check if the collision was in this step
            if (Rough.lessEqual(0, result.time) && Rough.lessEqual(result.time, timeToGo)) {
                // Move to collision point
                Vector move = new Vector(velocity).multiply(result.time);
                Transform.translate(position, move);

                // Calculate new velocity
                Vector normal = new Vector(result.getBestNormal(velocity));
                velocity.project(normal.antiNormal());

                // Time used up
                timeToGo -= result.time;
                if (Rough.lessEqual(timeToGo, 0)) {
                    // Done!
                    break;
                }
            } else {
                // No collision. Done!
                Vector velScaled = new Vector(velocity).multiply(timeToGo);
                Transform.translate(position, velScaled);
                break;
            }
        }
        // TODO: return correct normal
        return null;
    }
}
TOP

Related Classes of engine.utility.PhysicsDan$Collision

TOP
Copyright © 2018 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.