Skip to content

Commit

Permalink
Slope collision overhaul
Browse files Browse the repository at this point in the history
This adds support for `PostProcessingTiles`, which, when intersected, will receive a callback
allowing them to modify a CollisionResult after all collisions have been added. Thus, the Physics no
longer has special cases for handling slopes, as they can be handled with the new generic mechanism.

Also includes some new utility methods and some minor refactoring. Most notably, `hitbox` is now a
public field of the Entity class.
  • Loading branch information
Danjb1 committed Nov 1, 2019
1 parent 377dd73 commit e417cf8
Show file tree
Hide file tree
Showing 32 changed files with 2,313 additions and 1,301 deletions.
4 changes: 3 additions & 1 deletion demo/demo/game/entities/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ public class Player extends DemoEntity {
public Player(float x, float y) {
super(x, y, WIDTH, HEIGHT, DemoEntity.TYPE_PLAYER);

hitbox.setAirFrictionCoefficient(10f);
// Player should slow down dramatically in the air
hitbox.airFrictionCoefficient = 10f;

hitbox.setMaxSpeedX(MAX_SPEED_X);
}

Expand Down
19 changes: 17 additions & 2 deletions docs/TODO.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
# To Do

## Engine
## Features

- Support multiple Tile layers

- Support slopes with different gradients

- Support large entities on slopes (currently untested)

## Bugs

- 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 colliding with the left/right corners of a diamond

## Tech Debt

- Move more code from demo project to engine?

- Improve test coverage
- Improve test coverage (use reflection to test private methods)

## Demo

Expand Down
42 changes: 39 additions & 3 deletions src/engine/game/GameUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ public static float pxToWorld(int px) {
////////////////////////////////////////////////////////////////////////////

/**
* Returns either -1 or 1 at random.
* Multiplies the given value by either -1 or 1 at random.
*
* @param i
* @return
*/
public static int randomSign(int i) {
public static float randomSign(float i) {
return i * (Math.random() < 0.5 ? -1 : 1);
}

Expand Down Expand Up @@ -258,7 +258,7 @@ public static double randBetween(double min, double max, Random random) {
}

/**
* Returns a random int between the 2 limits.
* Returns a random int between the 2 limits (inclusive).
*
* @param min
* @param max
Expand All @@ -281,4 +281,40 @@ public static int randBetween(int min, int max, Random random) {
return min + (int)(random.nextDouble() * ((max - min) + 1));
}

/**
* Clamps an integer between 2 limits.
*
* @param val
* @param min
* @param max
* @return
*/
public static int clamp(int val, int min, int max) {
if (val < min) {
return min;
}
if (val > max) {
return max;
}
return val;
}

/**
* Clamps a float between 2 limits.
*
* @param val
* @param min
* @param max
* @return
*/
public static float clamp(float val, float min, float max) {
if (val < min) {
return min;
}
if (val > max) {
return max;
}
return val;
}

}
12 changes: 12 additions & 0 deletions src/engine/game/Level.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,25 @@ public boolean doesTileExist_X(int tileX) {

/**
* Determines if a tile co-ordinate is valid.
*
* @param tileY
* @return
*/
public boolean doesTileExist_Y(int tileY) {
return tileY >= 0 && tileY < getNumTilesY();
}

/**
* Determines if a tile co-ordinate is valid.
*
* @param tileX
* @param tileY
* @return
*/
public boolean doesTileExist(int tileX, int tileY) {
return doesTileExist_X(tileX) && doesTileExist_Y(tileY);
}

/**
* Gets the level width, in tiles.
*
Expand Down
4 changes: 2 additions & 2 deletions src/engine/game/entities/CameraSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public void entityTeleported() {
}

@Override
public void notify(ComponentEvent event) {
if (event instanceof EntityTeleported) {
public void notify(ComponentEvent eventBeforeCast) {
if (eventBeforeCast instanceof EntityTeleported) {
entityTeleported();
}
}
Expand Down
19 changes: 5 additions & 14 deletions src/engine/game/entities/Entity.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,18 @@ public abstract class Entity implements HitboxListener {
*/
public ComponentStore<EntityComponent> components = new ComponentStore<>();

/**
* This Entity's physical presence within the game world.
*/
public Hitbox hitbox;

/**
* Unique identifier used to refer to this Entity.
*
* <p>Assigned by the logic when the Entity is added to the world.
*/
protected int id = -1;

/**
* This Entity's physical presence within the game world.
*/
protected Hitbox hitbox;

/**
* Flag set when this Entity is marked for deletion.
*/
Expand Down Expand Up @@ -72,15 +72,6 @@ public Entity(float x, float y, float width, float height) {
// Getters
////////////////////////////////////////////////////////////////////////////

/**
* Gets this Entity's {@link Hitbox}.
*
* @return
*/
public Hitbox hitbox {
return hitbox;
}

/**
* Determines whether this Entity has been deleted.
*
Expand Down
79 changes: 49 additions & 30 deletions src/engine/game/physics/Collision.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package engine.game.physics;

import engine.game.physics.Hitbox.CollisionNode;
import engine.game.tiles.ForegroundTile;

/**
Expand All @@ -9,36 +10,48 @@
*/
public class Collision implements Comparable<Collision> {

/**
* Absolute position of the collision (x or y), in world units.
*/
public final float collisionPos;

/**
* Distance to the collision, in world units.
*/
private float distanceToCollision;
public final float distanceToCollision;

/**
* Absolute position of the collision (either x or y), in world units.
* The CollisionNode that triggered this Collision.
*/
private float collisionPos;
public final CollisionNode node;

/**
* Tile with which the collision occurred.
*/
private ForegroundTile tile;
public final ForegroundTile tile;

/**
* Whether this Collision is valid.
*/
protected boolean valid = true;

/**
* Constructor for a Collision.
* Constructs a Collision.
*
* @param hitboxPos
* Position of the relevant hitbox edge before the collision (x or y).
* Used to calculate the distance to the collision.
* @param collisionPos
* Position in the world where the collision occurred (x or y).
* @param tile Tile with which the collision occurred.
* @param node
* @param tile
* @param distanceToCollision
*/
public Collision(float hitboxPos, float collisionPos, ForegroundTile tile) {
private Collision(
float collisionPos,
CollisionNode node,
ForegroundTile tile,
float distanceToCollision) {
this.collisionPos = collisionPos;
this.node = node;
this.tile = tile;

distanceToCollision = collisionPos - hitboxPos;
this.distanceToCollision = distanceToCollision;
}

/**
Expand All @@ -49,27 +62,33 @@ public Collision(float hitboxPos, float collisionPos, ForegroundTile tile) {
@Override
public int compareTo(Collision other) {
float myDist = Math.abs(distanceToCollision);
float otherDist = Math.abs(other.getDistanceToCollision());
float otherDist = Math.abs(other.distanceToCollision);

if (myDist < otherDist) {
return -1;
} else if (myDist == otherDist) {
return 0;
} else {
return 1;
}
return Float.compare(myDist, otherDist);
}

public float getDistanceToCollision() {
return distanceToCollision;
}

public float getCollisionPos() {
return collisionPos;
}
////////////////////////////////////////////////////////////////////////////
// Factory Methods
////////////////////////////////////////////////////////////////////////////

public ForegroundTile getTile() {
return tile;
/**
* Creates a Collision.
*
* @param posBefore
* Absolute position of the relevant node before the collision.
* @param posAfter
* Absolute position of the relevant node after the collision.
* @param node The Node involved in this Collision.
* @param tile Tile with which the collision occurred.
* @return
*/
public static Collision create(
float posBefore,
float posAfter,
CollisionNode node,
ForegroundTile tile) {
float distanceToCollision = posAfter - posBefore;
return new Collision(posAfter, node, tile, distanceToCollision);
}

}
Loading

0 comments on commit e417cf8

Please sign in to comment.