Skip to content

Commit

Permalink
Fix slope corner case; add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Danjb1 committed Dec 6, 2019
1 parent e417cf8 commit 98c137e
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 27 deletions.
4 changes: 2 additions & 2 deletions docs/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
- Slopes:
- Non-slope-traversing Entities (e.g. projectiles) collide at the wrong place
- Occasional jittering at the bottom of ceiling slopes
- Jittering when a slope leads into a ceiling
- Strange behaviour when colliding with the wrong side of a slope tile
- Strange behaviour when a slope leads into a ceiling
- Strange behaviour when colliding with the "back" of a slope tile
- Strange behaviour when colliding with the left/right corners of a diamond

## Tech Debt
Expand Down
76 changes: 58 additions & 18 deletions src/engine/game/physics/Physics.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import engine.game.GameUtils;
import engine.game.Level;
import engine.game.Logic;
import engine.game.TileLayer;
import engine.game.physics.Hitbox.CollisionNode;
import engine.game.tiles.ForegroundTile;
import engine.game.tiles.PostProcessingTile;
Expand Down Expand Up @@ -221,27 +222,66 @@ public static CollisionResult getCollisionResult(
detectCollisionsX(result, logic, hitbox.getRightNodes());
}

// Check for collisions with any PostProcessingTiles at the new
// Hitbox position; we have to check this now because after the
// y-movement is applied, the Hitbox may no longer be colliding with
// a PostProcessingTile, so we will have missed the collision!
if (dx != 0) {
detectPostProcessCollisions(
result, logic, hitbox.getAllNodes(), false);
}

// Move in the y-axis
if (dy < 0) {
detectCollisionsY(result, logic, hitbox.getTopNodes());
} else if (dy > 0) {
detectCollisionsY(result, logic, hitbox.getBottomNodes());
}

// Check for collisions with any PostProcessingTiles at the final
// Hitbox position
/*
* POST-PROCESSING COLLISION DETECTION.
*
* STAGE 1:
* Check for PostProcessingCollisions at the initial Hitbox
* position.
*
* It may be that the Hitbox is already intersecting a
* PostProcessingTile, which affects which collisions are permitted.
*
* EXAMPLE:
* - Hitbox is on a right slope, moving right.
* - After the x-movement is applied, the Hitbox is no longer
* intersecting the slope but is intersecting the floor tile at
* the top of the slope.
* - An x-collision is registered, but no PostProcessingCollision
* is registered, so the x-collision never gets invalidated.
*/
detectPostProcessCollisions(
result, logic, hitbox.getAllNodes(), 0, 0);


/*
* STAGE 2:
* Check for PostProcessingCollisions after the x-movement is
* applied.
*
* It is possible that the x-movement could move the Hitbox into a
* PostProcessingTile, but the y-movement could move the Hitbox out
* of it, so we have to check for collisions before the y-movement
* is applied.
*
* EXAMPLE:
* - Hitbox is in the empty tile "between" 2 right slopes (above
* one, and left of the other), moving right.
* - After the x-movement is applied, the Hitbox intersects the
* slope immediately to the right.
* - Were we to apply the y-movement, the bottom node of the
* Hitbox would fall into the solid block BELOW the slope,
* therefore it would never be inside the slope.
*/
if (dx != 0) {
detectPostProcessCollisions(
result, logic, hitbox.getAllNodes(), dx, 0);
}

/*
* STAGE 3:
* Check for PostProcessingCollisions at the final Hitbox position.
*/
if (dy != 0) {
detectPostProcessCollisions(
result, logic, hitbox.getAllNodes(), true);
result, logic, hitbox.getAllNodes(), dx, dy);
}

result.finish();
Expand Down Expand Up @@ -320,13 +360,15 @@ private static void detectCollisionsY(
* @param result CollisionResult to update after detecting collisions.
* @param logic
* @param nodes
* @param afterYMovement
* @param dx
* @param dy
*/
private static void detectPostProcessCollisions(
CollisionResult result,
Logic logic,
Set<CollisionNode> nodes,
boolean afterYMovement) {
float dx,
float dy) {

Level level = logic.getLevel();

Expand All @@ -335,10 +377,8 @@ private static void detectPostProcessCollisions(
// Find the desired position of this CollisionNode
// (this ignores any previously-detected collisions, since they may
// be overridden by a PostProcessingCollision)
float nodeX = result.desiredNodeX(node);
float nodeY = afterYMovement
? result.desiredNodeY(node)
: result.initialNodeY(node);
float nodeX = result.initialNodeX(node) + dx;
float nodeY = result.initialNodeY(node) + dy;

// Find the tile which this node will intersect
int tileX = Tile.getTileX(nodeX);
Expand Down
50 changes: 43 additions & 7 deletions src/engine/game/tiles/Slope.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,21 +99,57 @@ protected boolean isCollisionValid_X(
int tileXBefore = Tile.getTileX(result.initialNodeX(collision.node));
int tileXAfter = Tile.getTileX(result.desiredNodeX(collision.node));
if (tileXBefore == tileXAfter) {
// Disable x-collisions if the CollisionNode was already
// intersecting the Tile in question
// (e.g. having been on a neighbouring slope)
/*
* Disable x-collisions if the CollisionNode was already
* intersecting the Tile in question.
*
* This can happen when the Hitbox moves from 1 slope to another.
*
* EXAMPLE:
* - Hitbox is on a right slope, moving right. The slope node is
* inside the slope, but the bottom-right node is intersecting
* the solid tile "behind" the slope.
* - After the attempted movement is applied, the Hitbox is no
* longer intersecting the same slope. It is intersecting the
* next slope tile (right and up), but the slope node is now
* inside the solid block below the new slope.
* - An x-collision is generated for the bottom-right node.
* This collision would normally be valid, since the slope node
* is not yet inside the new slope.
* - Because the node was ALREADY intersecting that solid block,
* the collision is invalidated - problem solved.
*/
return false;
}

if (result.initialNodeY(collision.node) < slopeCollision.getTileTop()) {
// Allow x-collisions triggered by CollisionNodes above the Slope
// (e.g. if a Slope leads into a wall)
/*
* Allow x-collisions triggered by CollisionNodes above the Slope
*
* This can happen if a Slope connects directly to a wall.
*
* EXAMPLE:
* - Hitbox is on a right slope, moving right.
* - The Hitbox collides with a wall at the top of the slope.
* - This collision is valid, because it is above the slope tile.
*/
return true;
}

if (result.initialNodeY(collision.node) > slopeCollision.getTileBottom()) {
// Allow x-collisions triggered by CollisionNodes below the Slope
// (e.g. if a Slope leads to a vertical drop)
/*
* Allow x-collisions triggered by CollisionNodes below the Slope
*
* This can happen if a Slope leads to a vertical drop.
*
* EXAMPLE:
* - Hitbox moves towards a right slope. There is a solid block
* tile directly below the slope.
* - The Hitbox collides in such a way that it intersects the
* slope, but also the solid block. An x-collision is
* generated.
* - This collision is valid, because it is below the slope tile.
*/
return true;
}

Expand Down

0 comments on commit 98c137e

Please sign in to comment.