diff --git a/src/com/blarg/gdx/math/SweptSphere.java b/src/com/blarg/gdx/math/SweptSphere.java new file mode 100644 index 0000000..a6dde19 --- /dev/null +++ b/src/com/blarg/gdx/math/SweptSphere.java @@ -0,0 +1,73 @@ +package com.blarg.gdx.math; + +import com.badlogic.gdx.math.Vector3; + +public class SweptSphere { + public final Vector3 position = new Vector3(); + + public boolean foundCollision; + public float nearestCollisionDistance; + public final Vector3 nearestCollisionPoint = new Vector3(); + public boolean isOnGround; + public boolean isSliding; + public final Vector3 slidingPlaneNormal = new Vector3(); + public final Vector3 slidingPlaneOrigin = new Vector3(); + + public final Vector3 radius = new Vector3(); + + // "ellipsoid space" fields, equivalent to the above similarly named fields + // they probably shouldn't be used directly + + public final Vector3 esPosition = new Vector3(); + public final Vector3 esVelocity = new Vector3(); + public final Vector3 esNormalizedVelocity = new Vector3(); + public final Vector3 esIntersectionPoint = new Vector3(); + + public void setRadius(float radius) { + this.radius.set(radius, radius, radius); + } + + public void setRadius(float radiusX, float radiusY, float radiusZ) { + this.radius.set(radiusX, radiusY, radiusZ); + } + + public void reset() { + position.set(Vector3.Zero); + foundCollision = false; + nearestCollisionDistance = 0.0f; + nearestCollisionPoint.set(Vector3.Zero); + isOnGround = false; + isSliding = false; + slidingPlaneNormal.set(Vector3.Zero); + slidingPlaneOrigin.set(Vector3.Zero); + radius.set(Vector3.Zero); + esPosition.set(Vector3.Zero); + esVelocity.set(Vector3.Zero); + esNormalizedVelocity.set(Vector3.Zero); + esIntersectionPoint.set(Vector3.Zero); + } + + public static void toEllipsoidSpace(Vector3 in, Vector3 ellipsoidRadius, Vector3 out) { + out.x = in.x / ellipsoidRadius.x; + out.y = in.y / ellipsoidRadius.y; + out.z = in.z / ellipsoidRadius.z; + } + + public static void toEllipsoidSpace(Vector3 v, Vector3 ellipsoidRadius) { + v.x /= ellipsoidRadius.x; + v.y /= ellipsoidRadius.y; + v.z /= ellipsoidRadius.z; + } + + public static void fromEllipsoidSpace(Vector3 in, Vector3 ellipsoidRadius, Vector3 out) { + out.x = in.x * ellipsoidRadius.x; + out.y = in.y * ellipsoidRadius.y; + out.z = in.z * ellipsoidRadius.z; + } + + public static void fromEllipsoidSpace(Vector3 v, Vector3 ellipsoidRadius) { + v.x *= ellipsoidRadius.x; + v.y *= ellipsoidRadius.y; + v.z *= ellipsoidRadius.z; + } +} diff --git a/src/com/blarg/gdx/math/SweptSphereCollisionPacket.java b/src/com/blarg/gdx/math/SweptSphereCollisionPacket.java deleted file mode 100644 index f270c68..0000000 --- a/src/com/blarg/gdx/math/SweptSphereCollisionPacket.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.blarg.gdx.math; - -import com.badlogic.gdx.math.Vector3; - -public final class SweptSphereCollisionPacket { - // defines the x/y/z radius of the entity being checked - public final Vector3 ellipsoidRadius = new Vector3(); - - public boolean foundCollision; - public float nearestDistance; - - // the below fields are all in "ellipsoid space" - - public final Vector3 esVelocity = new Vector3(); // velocity of the entity - public final Vector3 esNormalizedVelocity = new Vector3(); - public final Vector3 esPosition = new Vector3(); // current position of the entity - - public final Vector3 esIntersectionPoint = new Vector3(); // if an intersection is found - - public void toEllipsoidSpace(Vector3 v, Vector3 out) { - out.x = v.x / ellipsoidRadius.x; - out.y = v.y / ellipsoidRadius.y; - out.z = v.z / ellipsoidRadius.z; - } - - public void fromEllipsoidSpace(Vector3 v, Vector3 out) { - out.x = v.x * ellipsoidRadius.x; - out.y = v.y * ellipsoidRadius.y; - out.z = v.z * ellipsoidRadius.z; - } - - public void reset() { - ellipsoidRadius.set(Vector3.Zero); - foundCollision = false; - nearestDistance = 0.0f; - esVelocity.set(Vector3.Zero); - esNormalizedVelocity.set(Vector3.Zero); - esPosition.set(Vector3.Zero); - esIntersectionPoint.set(Vector3.Zero); - } -} diff --git a/src/com/blarg/gdx/math/SweptSphereCollisionTester.java b/src/com/blarg/gdx/math/SweptSphereCollisionTester.java index 8fdec90..71a6317 100644 --- a/src/com/blarg/gdx/math/SweptSphereCollisionTester.java +++ b/src/com/blarg/gdx/math/SweptSphereCollisionTester.java @@ -15,23 +15,23 @@ public final class SweptSphereCollisionTester { static final Vector3 edge = new Vector3(); static final Vector3 baseToVertex = new Vector3(); - public static boolean test(SweptSphereCollisionPacket packet, Vector3 v1, Vector3 v2, Vector3 v3) { + public static boolean test(SweptSphere sphere, Vector3 v1, Vector3 v2, Vector3 v3) { boolean foundCollision = false; - packet.toEllipsoidSpace(v1, p1); - packet.toEllipsoidSpace(v2, p2); - packet.toEllipsoidSpace(v3, p3); + SweptSphere.toEllipsoidSpace(v1, sphere.radius, p1); + SweptSphere.toEllipsoidSpace(v2, sphere.radius, p2); + SweptSphere.toEllipsoidSpace(v3, sphere.radius, p3); trianglePlane.set(p1, p2, p3); collisionPoint.set(Vector3.Zero); // Is the triangle front-facing to the entity's velocity? - if (trianglePlane.isFrontFacing(packet.esNormalizedVelocity)) { + if (trianglePlane.isFrontFacing(sphere.esNormalizedVelocity)) { float t0; float t1; boolean embeddedInPlane = false; - float distToTrianglePlane = trianglePlane.distance(packet.esPosition); - float normalDotVelocity = trianglePlane.normal.dot(packet.esVelocity); + float distToTrianglePlane = trianglePlane.distance(sphere.esPosition); + float normalDotVelocity = trianglePlane.normal.dot(sphere.esVelocity); // Is the sphere travelling parallel to the plane? if (normalDotVelocity == 0.0f) { @@ -75,9 +75,9 @@ public final class SweptSphereCollisionTester { // side of the triangle plane. if (!embeddedInPlane) { // planeIntersectionPoint = (packet.esPosition - trianglePlane.normal) + packet.esVelocity * t0 - tmp1.set(packet.esVelocity).scl(t0); + tmp1.set(sphere.esVelocity).scl(t0); planeIntersectionPoint - .set(packet.esPosition) + .set(sphere.esPosition) .sub(trianglePlane.normal) .add(tmp1); @@ -91,8 +91,8 @@ public final class SweptSphereCollisionTester { // If we haven't found a collision at this point, we need to check the // points and edges of the triangle if (!foundCollision) { - Vector3 velocity = packet.esVelocity; - Vector3 base = packet.esPosition; + Vector3 velocity = sphere.esVelocity; + Vector3 base = sphere.esPosition; float velocitySquaredLength = velocity.len2(); float a, b, c; float newT; @@ -206,13 +206,13 @@ public final class SweptSphereCollisionTester { // Set result of test if (foundCollision) { - float distanceToCollision = t * packet.esVelocity.len(); + float distanceToCollision = t * sphere.esVelocity.len(); // Does this triangle qualify for the closest collision? - if (!packet.foundCollision || distanceToCollision < packet.nearestDistance) { - packet.nearestDistance = distanceToCollision; - packet.esIntersectionPoint.set(collisionPoint); - packet.foundCollision = true; + if (!sphere.foundCollision || distanceToCollision < sphere.nearestCollisionDistance) { + sphere.nearestCollisionDistance = distanceToCollision; + sphere.esIntersectionPoint.set(collisionPoint); + sphere.foundCollision = true; } } } diff --git a/src/com/blarg/gdx/math/SweptSphereEntity.java b/src/com/blarg/gdx/math/SweptSphereEntity.java deleted file mode 100644 index 5aca89f..0000000 --- a/src/com/blarg/gdx/math/SweptSphereEntity.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.blarg.gdx.math; - -import com.badlogic.gdx.math.Vector3; - -public class SweptSphereEntity { - public final Vector3 position = new Vector3(); - - public boolean foundCollision; - public final Vector3 nearestCollisionPoint = new Vector3(); - public boolean isSliding; - public final Vector3 slidingPlaneNormal = new Vector3(); - - public final SweptSphereCollisionPacket collisionPacket = new SweptSphereCollisionPacket(); - - public SweptSphereEntity() { - } - - public void setSize(float radius) { - collisionPacket.ellipsoidRadius.set(radius, radius, radius); - } - - public void setSize(float radiusX, float radiusY, float radiusZ) { - collisionPacket.ellipsoidRadius.set(radiusX, radiusY, radiusZ); - } -} diff --git a/src/com/blarg/gdx/math/SweptSphereHandler.java b/src/com/blarg/gdx/math/SweptSphereHandler.java index 30435c8..521a402 100644 --- a/src/com/blarg/gdx/math/SweptSphereHandler.java +++ b/src/com/blarg/gdx/math/SweptSphereHandler.java @@ -25,36 +25,38 @@ public class SweptSphereHandler { this.maxRecursionDepth = maxRecursionDepth; } - public void handleMovement(SweptSphereEntity entity, Vector3 velocity, Vector3 outVelocity, boolean onlySlideIfTooSteep, float tooSteepAngleY) { + public void handleMovement(SweptSphere sphere, Vector3 velocity, Vector3 outVelocity, boolean onlySlideIfTooSteep, float tooSteepAngleY) { // don't attempt to process movement if the entity is not moving! if (velocity.len2() > 0.0f) { // calculate maximum possible collision area (world space) - calculatePossibleCollisionArea(entity, velocity); + calculatePossibleCollisionArea(sphere, velocity); // convert position and velocity to ellipsoid space Vector3 esPosition = new Vector3(); Vector3 esVelocity = new Vector3(); - entity.collisionPacket.toEllipsoidSpace(entity.position, esPosition); - entity.collisionPacket.toEllipsoidSpace(velocity, esVelocity); + SweptSphere.toEllipsoidSpace(sphere.position, sphere.radius, esPosition); + SweptSphere.toEllipsoidSpace(velocity, sphere.radius, esVelocity); // check for and respond to any collisions along this velocity vector - entity.collisionPacket.nearestDistance = 0.0f; - entity.collisionPacket.foundCollision = false; - entity.collisionPacket.esIntersectionPoint.set(Vector3.Zero); + sphere.nearestCollisionDistance = 0.0f; + sphere.foundCollision = false; + sphere.esIntersectionPoint.set(Vector3.Zero); Vector3 resultingVelocity = new Vector3(); - Vector3 newEsPosition = getNewPositionForMovement(0, entity, esPosition, esVelocity, resultingVelocity, true, onlySlideIfTooSteep, tooSteepAngleY); + Vector3 newEsPosition = getNewPositionForMovement(0, sphere, esPosition, esVelocity, resultingVelocity, true, onlySlideIfTooSteep, tooSteepAngleY); // resulting velocity will have been calculated in ellipsoid space - entity.collisionPacket.fromEllipsoidSpace(resultingVelocity, resultingVelocity); + SweptSphere.fromEllipsoidSpace(resultingVelocity, sphere.radius); - entity.foundCollision = entity.collisionPacket.foundCollision; - if (entity.collisionPacket.foundCollision) - entity.collisionPacket.fromEllipsoidSpace(entity.collisionPacket.esIntersectionPoint, entity.nearestCollisionPoint); + if (sphere.foundCollision) + SweptSphere.fromEllipsoidSpace(sphere.esIntersectionPoint, sphere.radius, sphere.nearestCollisionPoint); else - entity.nearestCollisionPoint.set(Vector3.Zero); + sphere.nearestCollisionPoint.set(Vector3.Zero); + + // sliding plane origin will be in ellipsoid space still... + SweptSphere.fromEllipsoidSpace(sphere.slidingPlaneOrigin, sphere.radius); // convert the new position back to normal space and move the entity there - entity.collisionPacket.fromEllipsoidSpace(newEsPosition, entity.position); + SweptSphere.fromEllipsoidSpace(newEsPosition, sphere.radius, sphere.position); outVelocity.set(resultingVelocity); } @@ -63,7 +65,7 @@ public class SweptSphereHandler { } private Vector3 getNewPositionForMovement(int recursionDepth, - SweptSphereEntity entity, + SweptSphere sphere, Vector3 currentPosition, Vector3 velocity, Vector3 responseVelocity, @@ -77,16 +79,16 @@ public class SweptSphereHandler { responseVelocity.set(velocity); // set up the collision check information - entity.collisionPacket.esVelocity.set(velocity); - entity.collisionPacket.esNormalizedVelocity.set(velocity.nor()); - entity.collisionPacket.esPosition.set(currentPosition); - entity.collisionPacket.foundCollision = false; + sphere.esVelocity.set(velocity); + sphere.esNormalizedVelocity.set(velocity.nor()); + sphere.esPosition.set(currentPosition); + sphere.foundCollision = false; // perform the check - collisionChecker.checkForCollisions(entity, possibleCollisionArea); + collisionChecker.checkForCollisions(sphere, possibleCollisionArea); // if there was no collision, simply move along the velocity vector - if (!entity.collisionPacket.foundCollision) + if (!sphere.foundCollision) return new Vector3(currentPosition).add(velocity); // a collision did occur @@ -94,12 +96,12 @@ public class SweptSphereHandler { Vector3 destination = new Vector3(currentPosition).add(velocity); Vector3 newPosition = new Vector3(currentPosition); - if (entity.collisionPacket.nearestDistance >= collisionVeryCloseDistance) { + if (sphere.nearestCollisionDistance >= collisionVeryCloseDistance) { // we haven't yet moved up too close to the nearest collision, so // let's inch forward a bit // figure out the new position that we need to move up to - float moveUpLength = entity.collisionPacket.nearestDistance - collisionVeryCloseDistance; + float moveUpLength = sphere.nearestCollisionDistance - collisionVeryCloseDistance; // HACK: if the above length ends up being 0, "v" calculated below will // end up with "NaN" x/y/z components which will eventually cause @@ -109,18 +111,18 @@ public class SweptSphereHandler { // still very small (below the VERY_CLOSE_DISTANCE threshold) then // it appears to work fine. if (moveUpLength == 0.0f) - moveUpLength = entity.collisionPacket.nearestDistance - (collisionVeryCloseDistance * 0.5f); + moveUpLength = sphere.nearestCollisionDistance - (collisionVeryCloseDistance * 0.5f); tmp1.set(velocity); MathHelpers.setLengthOf(tmp1, moveUpLength); - newPosition.set(entity.collisionPacket.esPosition).add(tmp1); + newPosition.set(sphere.esPosition).add(tmp1); // adjust the polygon intersection point, so the sliding plane will be // unaffected by the fact that we move slightly less than the collision // tells us tmp1.nor(); tmp1.scl(collisionVeryCloseDistance); - entity.collisionPacket.esIntersectionPoint.sub(tmp1); + sphere.esIntersectionPoint.sub(tmp1); } if (!canSlide) { @@ -129,27 +131,26 @@ public class SweptSphereHandler { } // we can slide, so determine the sliding plane - Vector3 slidePlaneOrigin = new Vector3(entity.collisionPacket.esIntersectionPoint); - Vector3 slidePlaneNormal = new Vector3(newPosition).sub(entity.collisionPacket.esIntersectionPoint).nor(); - Plane slidingPlane = new Plane(slidePlaneOrigin, slidePlaneNormal); + sphere.slidingPlaneOrigin.set(sphere.esIntersectionPoint); + sphere.slidingPlaneNormal.set(newPosition).sub(sphere.esIntersectionPoint).nor(); + Plane slidingPlane = new Plane(sphere.slidingPlaneNormal, sphere.slidingPlaneOrigin); // determine slide angle and then check if we need to bail out on sliding // depending on how steep the slide plane is - entity.slidingPlaneNormal.set(slidePlaneNormal); - float slidingYAngle = (float)Math.acos(slidePlaneNormal.dot(Vector3.Y)); + float slidingYAngle = (float)Math.acos(sphere.slidingPlaneNormal.dot(Vector3.Y)); if (onlySlideIfTooSteep && slidingYAngle < (tooSteepAngleY * MathUtils.degreesToRadians)) { responseVelocity.set(Vector3.Zero); return newPosition; } - tmp1.set(slidePlaneNormal).scl(slidingPlane.distance(destination)); + tmp1.set(sphere.slidingPlaneNormal).scl(slidingPlane.distance(destination)); Vector3 newDestination = new Vector3(destination).sub(tmp1); // generate the slide vector, which will become our new velocity vector // for the next iteration - entity.isSliding = true; - Vector3 newVelocity = new Vector3(newDestination).sub(entity.collisionPacket.esIntersectionPoint); + sphere.isSliding = true; + Vector3 newVelocity = new Vector3(newDestination).sub(sphere.esIntersectionPoint); responseVelocity.set(newVelocity); // don't recurse if the velocity is very small @@ -158,20 +159,20 @@ public class SweptSphereHandler { // recurse ++recursionDepth; - return getNewPositionForMovement(recursionDepth, entity, newPosition, newVelocity, responseVelocity, canSlide, onlySlideIfTooSteep, tooSteepAngleY); + return getNewPositionForMovement(recursionDepth, sphere, newPosition, newVelocity, responseVelocity, canSlide, onlySlideIfTooSteep, tooSteepAngleY); } - private void calculatePossibleCollisionArea(SweptSphereEntity entity, Vector3 velocity) { - tmp1.set(entity.position).add(velocity); // the "end" position - Vector3 radius = entity.collisionPacket.ellipsoidRadius; + private void calculatePossibleCollisionArea(SweptSphere sphere, Vector3 velocity) { + tmp1.set(sphere.position).add(velocity); // the "end" position + Vector3 radius = sphere.radius; - possibleCollisionArea.min.x = Math.min(entity.position.x, tmp1.x) - radius.x; - possibleCollisionArea.min.y = Math.min(entity.position.y, tmp1.y) - radius.y; - possibleCollisionArea.min.z = Math.min(entity.position.z, tmp1.z) - radius.z; + possibleCollisionArea.min.x = Math.min(sphere.position.x, tmp1.x) - radius.x; + possibleCollisionArea.min.y = Math.min(sphere.position.y, tmp1.y) - radius.y; + possibleCollisionArea.min.z = Math.min(sphere.position.z, tmp1.z) - radius.z; - possibleCollisionArea.max.x = Math.max(entity.position.x, tmp1.x) + radius.x; - possibleCollisionArea.max.y = Math.max(entity.position.y, tmp1.y) + radius.y; - possibleCollisionArea.max.z = Math.max(entity.position.z, tmp1.z) + radius.z; + possibleCollisionArea.max.x = Math.max(sphere.position.x, tmp1.x) + radius.x; + possibleCollisionArea.max.y = Math.max(sphere.position.y, tmp1.y) + radius.y; + possibleCollisionArea.max.z = Math.max(sphere.position.z, tmp1.z) + radius.z; } } diff --git a/src/com/blarg/gdx/math/SweptSphereWorldCollisionChecker.java b/src/com/blarg/gdx/math/SweptSphereWorldCollisionChecker.java index 3b0a1de..d2d110c 100644 --- a/src/com/blarg/gdx/math/SweptSphereWorldCollisionChecker.java +++ b/src/com/blarg/gdx/math/SweptSphereWorldCollisionChecker.java @@ -3,5 +3,5 @@ package com.blarg.gdx.math; import com.badlogic.gdx.math.collision.BoundingBox; public interface SweptSphereWorldCollisionChecker { - void checkForCollisions(SweptSphereEntity entity, BoundingBox possibleCollisionArea); + void checkForCollisions(SweptSphere sphere, BoundingBox possibleCollisionArea); }