The Logic
The player which is a cube (32 by 32 pixels) checks if their is a cell next to it that has the name Wall. (This is done using a tileset).
To do this collision check I made four checks in this order:
- Is their a wall under the player.
- Is their a wall to the left of the player.
- Is their a wall to the right of the player.
- Is their a wall above the player.
If the player for example touches the wall to the left of him The x coordinates of the player are set to the tile right of the wall(cell) that was collided with.
The Problem
If for example I move the player left, the loop will first check for a collision under the player however this makes the player move up if their is a wall to the left of the player which he is touching. (Note: it doesn't always do this only if the player moved enough pixels to the left). The player should have just stopped moving to the left. Moving up was not desired.
Experiments
I tried adding the left and right check for collision first. This way the bottom check should not see the cell. This made the player teleport to the left and right of the cell the player was currently on because gravity has time now to drag the player down enough pixels. (The player is always affected by gravity and I rather not change this for it wouldn't make sense for an entity like the player to not be affected by it).
Making the movement speed of the player smaller. This did have an affect which was more desired but the players movement speed should not be effected at all as a fix.
The Code
Collision detection code
// Floor collision
if (map.isWall(xCoordinates, yCoordinates - 1) || map.isWall(xCoordinates + 31, yCoordinates - 1))
yCoordinates = ((int)(yCoordinates / 32) * 32) + 32;
// Left collision
if (map.isWall(xCoordinates - 1, yCoordinates) || map.isWall(xCoordinates - 1, yCoordinates + 32)) {
xCoordinates = ((int)((xCoordinates - 1) / 32) * 32) + 32;
canMoveLeft = false;
} else
canMoveLeft = true;
// Right collision
if (map.isWall(xCoordinates + 32, yCoordinates) || map.isWall(xCoordinates + 32, yCoordinates + 32)) {
xCoordinates = ((int)(xCoordinates / 32) * 32);
canMoveRight = false;
} else
canMoveRight = true;
// Roof collision
if (map.isWall(xCoordinates, yCoordinates + 32) || map.isWall(xCoordinates + 31, yCoordinates + 32)) {
canGoUp = false;
}
The isWall function
public Cell getCellByPixel(float cellPositionX, float cellPositionY) {
if (cellPositionX >= 0 && cellPositionY >= 0)
if (tileid.getCell((int)cellPositionX / 32, (int)cellPositionY / 32) != null)
return tileid.getCell((int)cellPositionX / 32, (int)cellPositionY / 32 );
return null;
}
private TiledMapTile getTileByPixel(float cellPositionX, float cellPositionY) {
if (getCellByPixel(cellPositionX, cellPositionY) != null)
if (getCellByPixel(cellPositionX, cellPositionY).getTile() != null)
return getCellByPixel(cellPositionX, cellPositionY).getTile();
return null;
}
// Check if the cell has a tile with the property of Wall. We can see this in the tsx file.
public boolean isWall(float cellPositionX, float cellPositionY) {
if (getTileByPixel(cellPositionX, cellPositionY) != null)
if (getTileByPixel(cellPositionX, cellPositionY).getProperties().get("Wall") != null)
return true;
return false;
}
Player movement
private void Movement() {
if (canMoveLeft)
if (Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT))
xCoordinates -= (playerMovementSpeed * Gdx.graphics.getDeltaTime());
if (canMoveRight)
if (Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT))
xCoordinates += (playerMovementSpeed * Gdx.graphics.getDeltaTime());
}