It took me many days to create a working collision detection for a 2D java platformer. I am finally calculating the corners of my player but the system is still buggy and I hope that we can figure out the problem.
This is a part of my Entity class. First, I calculate the movement in which direction the entity is moving or if it is falling or jumping and determine my dx and dy fields. After that I check the collision by calculating the corners and set dx or dy to zero if something is blocking the entity. Finally, I perform the moving by adding dx and dy to the x and y position:
public abstract class Entity extends GameObject {
//constants
private final float GRAVITY = 0.2F;
private final float MAX_FALLING_SPEED = 2.5F;
private final float JUMP_START = -3.5F;
//movement
protected float dx;
protected float dy;
protected float speed;
//movement action
protected boolean right;
protected boolean left;
protected boolean falling;
protected boolean jumping;
//collision
protected boolean topLeft;
protected boolean topRight;
protected boolean bottomLeft;
protected boolean bottomRight;
protected boolean midLeft;
protected boolean midRight;
protected boolean hasfallen;
public Entity(float x, float y, int width, int height, float speed) {
super(x, y, width, height);
this.speed = speed;
}
public void update() {
calculateMovement(); //1
calculateCollisions(); //2
move(); //3
}
private void calculateMovement() {
if(left) dx = -speed;
if(right) dx = speed;
if(falling && !jumping) {
dy += GRAVITY;
if(dy > MAX_FALLING_SPEED) dy = MAX_FALLING_SPEED;
}
if(jumping && !falling) {
dy = JUMP_START;
jumping = false;
falling = true;
}
}
private void calculateCollisions() {
float tox = x + dx;
float toy = y + dy;
//LEFT AND RIGHT COLLISION
calculateCorners(tox, y);
if(dx < 0) {
if(topLeft || bottomLeft || midLeft) {
dx = 0;
}
}
if(dx > 0) {
if(topRight || bottomRight || midRight) {
dx = 0;
}
}
//BOTTOM AND TOP (FALLING) COLLISION
calculateCorners(x, toy);
if(bottomLeft || bottomRight && falling) {
falling = false;
dy = 0;
}
if(!bottomLeft && !bottomRight) {
falling = true;
}
//here's the error, he is constantly switching
//between false and true for both booleans after
//the entity hit the ground
System.out.println(bottomLeft + " " + bottomRight);
}
private void calculateCorners(float x, float y) {
World world = Playstate.world;
int leftTile = world.getColTile((int)x);
int rightTile = world.getColTile((int)x + width - 1);
int topTile = world.getRowTile((int)y);
int bottomTile = world.getRowTile((int)y + height - 1);
int midTile = world.getRowTile((int)y + height / 2);
topLeft = !world.getBlocks()[topTile][leftTile].getMaterial().isWalkable();
bottomLeft = !world.getBlocks()[bottomTile][leftTile].getMaterial().isWalkable();
topRight = !world.getBlocks()[topTile][rightTile].getMaterial().isWalkable();
bottomRight = !world.getBlocks()[bottomTile][rightTile].getMaterial().isWalkable();
midLeft = !world.getBlocks()[midTile][leftTile].getMaterial().isWalkable();
midRight = !world.getBlocks()[midTile][rightTile].getMaterial().isWalkable();
}
private void move() {
x += dx;
y += dy;
dx = 0;
}
}
The left and right collision work fine. The problem occurs when the entity hit the ground and falling stops. For example after falling my console says my entity is at position y: 44.9 but it should be 50 to fit to the tile. Apart from that, as you can see I checked the bottomLeft and bottomRight in my calculateCollisions()
method. The console returns constantly true and false so in conclusion my entity is switching between falling and not falling fastly. Finally this causes a bug that you can't jump sometimes because if the entity is falling, jumping is set to false. So the entity will only jump if you hit the right moment when bottomLeft and bottomRight are true.