diff --git a/core/src/de/samdev/colorrunner/game/world/entities/MovingEntity.java b/core/src/de/samdev/colorrunner/game/world/entities/MovingEntity.java index 89591b2..2dae8b7 100644 --- a/core/src/de/samdev/colorrunner/game/world/entities/MovingEntity.java +++ b/core/src/de/samdev/colorrunner/game/world/entities/MovingEntity.java @@ -9,9 +9,9 @@ import de.samdev.colorrunner.game.world.CRGameWorld; public abstract class MovingEntity extends CRGameEntity { protected Vector2 velocity = new Vector2(); - public final static float COLL_PUSHBACK_EPSILON = 1e-5F; - public final static float COLL_DETECT_EPSILON = 2e-5f; - public final static float EXPAND_EPSILON = 1e-6f; + public final static float EPSILON_TOUCH = 4e-5f; + public final static float EPSILON_MOVE = 2e-5f; + public final static float EPSILON_COLLIDE = 1e-5f; private boolean face_TOP_isTouching = false; private boolean face_LEFT_isTouching = false; @@ -34,36 +34,35 @@ public abstract class MovingEntity extends CRGameEntity { Rectangle next = new Rectangle(bounds); next.x += bx; - next.set(next.x - COLL_PUSHBACK_EPSILON, next.y - COLL_PUSHBACK_EPSILON, next.width + 2*COLL_PUSHBACK_EPSILON, next.height + 2*COLL_PUSHBACK_EPSILON); for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(next) && ent.canCollide(true, this)) { + if (overlaps(ent.bounds, next, EPSILON_MOVE) && ent.canCollide(true, this)) { - if (ent.bounds.overlaps(bounds)) { + if (overlaps(ent.bounds, bounds, EPSILON_COLLIDE)) { Gdx.app.log("Collision", "Ignore in bounds collision"); continue; } if (bx < 0) { // DOWN - float correction = (ent.bounds.x + ent.bounds.height) - next.x; + float correction = (ent.bounds.x + ent.bounds.height) - next.x + EPSILON_MOVE; next.x += correction; bx += correction; - if (bx >= -COLL_PUSHBACK_EPSILON) - return true; // collision but no movement + if (bx >= -EPSILON_MOVE) + return false; // collision but no movement collided = true; } else { // UP - float correction = ent.bounds.x - (next.x + next.height); + float correction = ent.bounds.x - (next.x + next.height) - EPSILON_MOVE; next.x += correction; bx += correction; - if (bx <= COLL_PUSHBACK_EPSILON) - return true; // collision but no movement + if (bx <= EPSILON_MOVE) + return false; // collision but no movement collided = true; } @@ -82,35 +81,34 @@ public abstract class MovingEntity extends CRGameEntity { Rectangle next = new Rectangle(bounds); next.y += by; - next.set(next.x - COLL_PUSHBACK_EPSILON, next.y - COLL_PUSHBACK_EPSILON, next.width + 2*COLL_PUSHBACK_EPSILON, next.height + 2*COLL_PUSHBACK_EPSILON); - + for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(next) && ent.canCollide(true, this)) { + if (overlaps(next, ent.bounds, EPSILON_MOVE) && ent.canCollide(true, this)) { - if (ent.bounds.overlaps(bounds)) { + if (overlaps(bounds, ent.bounds, EPSILON_COLLIDE)) { Gdx.app.log("Collision", "Ignore in bounds collision"); continue; } if (by < 0) { // DOWN - float correction = (ent.bounds.y + ent.bounds.height) - next.y; + float correction = (ent.bounds.y + ent.bounds.height) - next.y + EPSILON_MOVE; next.y += correction; by += correction; - if (by >= -COLL_PUSHBACK_EPSILON) + if (by >= -EPSILON_MOVE) return true; // collision but no movement collided = true; } else { // UP - float correction = ent.bounds.y - (next.y + next.height); + float correction = ent.bounds.y - (next.y + next.height) - EPSILON_MOVE; next.y += correction; by += correction; - if (by <= COLL_PUSHBACK_EPSILON) + if (by <= EPSILON_MOVE) return true; // collision but no movement collided = true; @@ -149,36 +147,34 @@ public abstract class MovingEntity extends CRGameEntity { bounds.set(next); return true; } else { - next.set(next.x - COLL_PUSHBACK_EPSILON, next.y - COLL_PUSHBACK_EPSILON, next.width + 2*COLL_PUSHBACK_EPSILON, next.height + 2*COLL_PUSHBACK_EPSILON); - for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(next) && ent.canCollide(false, this)) { + if (overlaps(ent.bounds, next, EPSILON_MOVE) && ent.canCollide(false, this)) { - if (ent.bounds.overlaps(bounds)) { + if (overlaps(ent.bounds, bounds, EPSILON_COLLIDE)) { Gdx.app.log("Collision", "Ignore in bounds collision on HB Expand [X]"); continue; } if (ent.bounds.x > next.x) { - next.x -= (next.x + next.width) - ent.bounds.x; + next.x -= (next.x + next.width) - ent.bounds.x - EPSILON_MOVE; for (CRGameEntity ent2 : world.entities) { if (ent2 == this) continue; - if (ent2.bounds.overlaps(next) && ent2.canCollide(false, this)) { + if (overlaps(next, ent2.bounds, EPSILON_COLLIDE) && ent2.canCollide(false, this)) { Gdx.app.log("Entity Hitbox", "Expand failed X+"); return false; } } } else if (ent.bounds.x < next.x) { - next.x += (ent.bounds.x + ent.bounds.width) - next.x; + next.x += (ent.bounds.x + ent.bounds.width) - next.x + EPSILON_MOVE; for (CRGameEntity ent2 : world.entities) { if (ent2 == this) continue; - if (ent2.bounds.overlaps(next) && ent2.canCollide(false, this)) { + if (overlaps(next, ent2.bounds, EPSILON_COLLIDE) && ent2.canCollide(false, this)) { Gdx.app.log("Entity Hitbox", "Expand failed X-"); return false; } @@ -187,7 +183,7 @@ public abstract class MovingEntity extends CRGameEntity { } } - bounds.set(next.x + COLL_PUSHBACK_EPSILON, next.y + COLL_PUSHBACK_EPSILON, next.width - 2*COLL_PUSHBACK_EPSILON, next.height - 2*COLL_PUSHBACK_EPSILON); + bounds.set(next); return true; } } @@ -207,41 +203,38 @@ public abstract class MovingEntity extends CRGameEntity { next.y -= add/2; } - if (add < 0) { bounds.set(next); return true; } else { - next.set(next.x - COLL_PUSHBACK_EPSILON, next.y - COLL_PUSHBACK_EPSILON, next.width + 2*COLL_PUSHBACK_EPSILON, next.height + 2*COLL_PUSHBACK_EPSILON); - for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(next) && ent.canCollide(false, this)) { + if (overlaps(ent.bounds, next, EPSILON_MOVE) && ent.canCollide(false, this)) { - if (ent.bounds.overlaps(bounds)) { + if (overlaps(ent.bounds, bounds, EPSILON_COLLIDE)) { Gdx.app.log("Collision", "Ignore in bounds collision on HB Expand [Y]"); continue; } if (ent.bounds.y > next.y) { - next.y -= (next.y + next.height) - ent.bounds.y; + next.y -= (next.y + next.height) - ent.bounds.y - EPSILON_MOVE; for (CRGameEntity ent2 : world.entities) { if (ent2 == this) continue; - if (ent2.bounds.overlaps(next) && ent2.canCollide(false, this)) { + if (overlaps(next, ent2.bounds, EPSILON_COLLIDE) && ent2.canCollide(false, this)) { Gdx.app.log("Entity Hitbox", "Expand failed Y+"); return false; } } } else if (ent.bounds.y < next.y) { - next.y += (ent.bounds.y + ent.bounds.height) - next.y; + next.y += (ent.bounds.y + ent.bounds.height) - next.y + EPSILON_MOVE; for (CRGameEntity ent2 : world.entities) { if (ent2 == this) continue; - if (ent2.bounds.overlaps(next) && ent2.canCollide(false, this)) { + if (overlaps(next, ent2.bounds, EPSILON_COLLIDE) && ent2.canCollide(false, this)) { Gdx.app.log("Entity Hitbox", "Expand failed Y-"); return false; } @@ -250,7 +243,6 @@ public abstract class MovingEntity extends CRGameEntity { } } - bounds.set(next.x + COLL_PUSHBACK_EPSILON, next.y + COLL_PUSHBACK_EPSILON, next.width - 2*COLL_PUSHBACK_EPSILON, next.height - 2*COLL_PUSHBACK_EPSILON); return true; } } @@ -264,19 +256,19 @@ public abstract class MovingEntity extends CRGameEntity { for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (Math.abs((ent.bounds.y + ent.bounds.height) - bounds.y) < COLL_DETECT_EPSILON && ent.bounds.x < (bounds.x + bounds.width) && (ent.bounds.x + ent.bounds.width) > bounds.x && ent.canCollide(false, this)) { + if (Math.abs((ent.bounds.y + ent.bounds.height) - bounds.y) < EPSILON_TOUCH && ent.bounds.x < (bounds.x + bounds.width) && (ent.bounds.x + ent.bounds.width) > bounds.x && ent.canCollide(false, this)) { face_BOTTOM_isTouching = true; } - if (Math.abs((bounds.y + bounds.height) - ent.bounds.y) < COLL_DETECT_EPSILON && ent.bounds.x < (bounds.x + bounds.width) && (ent.bounds.x + ent.bounds.width) > bounds.x && ent.canCollide(false, this)) { + if (Math.abs((bounds.y + bounds.height) - ent.bounds.y) < EPSILON_TOUCH && ent.bounds.x < (bounds.x + bounds.width) && (ent.bounds.x + ent.bounds.width) > bounds.x && ent.canCollide(false, this)) { face_TOP_isTouching = true; } - if (Math.abs((bounds.x + bounds.width) - ent.bounds.x) < COLL_DETECT_EPSILON && ent.bounds.y < (bounds.y + bounds.height) && (ent.bounds.y + ent.bounds.height) > bounds.y && ent.canCollide(false, this)) { + if (Math.abs((bounds.x + bounds.width) - ent.bounds.x) < EPSILON_TOUCH && ent.bounds.y < (bounds.y + bounds.height) && (ent.bounds.y + ent.bounds.height) > bounds.y && ent.canCollide(false, this)) { face_RIGHT_isTouching = true; } - if (Math.abs((ent.bounds.x + ent.bounds.width) - bounds.x) < COLL_DETECT_EPSILON && ent.bounds.y < (bounds.y + bounds.height) && (ent.bounds.y + ent.bounds.height) > bounds.y && ent.canCollide(false, this)) { + if (Math.abs((ent.bounds.x + ent.bounds.width) - bounds.x) < EPSILON_TOUCH && ent.bounds.y < (bounds.y + bounds.height) && (ent.bounds.y + ent.bounds.height) > bounds.y && ent.canCollide(false, this)) { face_LEFT_isTouching = true; } } @@ -295,7 +287,7 @@ public abstract class MovingEntity extends CRGameEntity { } for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(bounds) && ent.canCollide(true, this)) + if (overlaps(ent.bounds, bounds, EPSILON_COLLIDE) && ent.canCollide(true, this)) Gdx.app.error("Collision", "Collision after move X"); } } @@ -306,7 +298,7 @@ public abstract class MovingEntity extends CRGameEntity { } for (CRGameEntity ent : world.entities) { if (ent == this) continue; - if (ent.bounds.overlaps(bounds) && ent.canCollide(true, this)) + if (overlaps(ent.bounds, bounds, EPSILON_COLLIDE) && ent.canCollide(true, this)) Gdx.app.error("Collision", "Collision after Y"); } } @@ -316,6 +308,15 @@ public abstract class MovingEntity extends CRGameEntity { updateTouchCollisions(); } + + private boolean overlaps (Rectangle r1, Rectangle r2, float delta) { + return + r1.x - 1*delta < r2.x + r2.width && + r1.x + r1.width + 2*delta > r2.x && + r1.y - 1*delta < r2.y + r2.height && + r1.y + r1.height + 2*delta > r2.y; + } + public boolean isTouching_ANY() { return face_TOP_isTouching || face_LEFT_isTouching || face_BOTTOM_isTouching || face_RIGHT_isTouching; }