I’m working on a 2D Top-Down RPG and facing an issue with my collision detection. I have two classes: Entity.java and CollisionManager.java.
The Entity class contains attributes like speed and a BoundingBox (represented by a Rectangle object). Before moving the entity, I call a method from the CollisionManager class to check for collisions with the tiles.
The problem is that when I increase the entity’s speed, the collision is detected too early, a few pixels before the entity actually reaches the tile.
CollisionManager.java (checkTile method):
public void checkTile(Entity entity) {
int entityLeftWorldX = entity.worldX + entity.boundingBox.x;
int entityRightWorldX = entityLeftWorldX + entity.boundingBox.width; // Cambiato per maggiore chiarezza
int entityTopWorldY = entity.worldY + entity.boundingBox.y;
int entityBottomWorldY = entityTopWorldY + entity.boundingBox.height; // Cambiato per maggiore chiarezza
int entityLeftColumn = entityLeftWorldX / wm.TILE_SIZE;
int entityRightColumn = entityRightWorldX / wm.TILE_SIZE;
int entityTopRow = entityTopWorldY / wm.TILE_SIZE;
int entityBottomRow = entityBottomWorldY / wm.TILE_SIZE;
switch (entity.currentDirection) {
case UP -> entityTopRow = (entityTopWorldY - entity.speed) / wm.TILE_SIZE;
case DOWN -> entityBottomRow = (entityBottomWorldY + entity.speed) / wm.TILE_SIZE;
case LEFT -> entityLeftColumn = (entityLeftWorldX - entity.speed) / wm.TILE_SIZE;
case RIGHT -> entityRightColumn = (entityRightWorldX + entity.speed) / wm.TILE_SIZE;
}
int[] topTiles = {
wm.firstLayerMap.GAME_MAP[entityLeftColumn][entityTopRow],
wm.firstLayerMap.GAME_MAP[entityRightColumn][entityTopRow]
};
int[] bottomTiles = {
wm.firstLayerMap.GAME_MAP[entityLeftColumn][entityBottomRow],
wm.firstLayerMap.GAME_MAP[entityRightColumn][entityBottomRow]
};
if (isTileColliding(topTiles) || isTileColliding(bottomTiles)) {
entity.isColliding = true;
}
}
private boolean isTileColliding(int... tileNums) {
for (int tileNum : tileNums) {
if (tileNum >= 0 && isTileSolid(tileNum, wm.firstLayerMap)) {
return true;
}
}
return false;
}
private boolean isTileSolid(int tileNum, TileManager layer) {
return layer != null && layer.tileMap.get(tileNum) != null && layer.tileMap.get(tileNum).isSolid;
}
Call to the method in Entity.java:
private void updatePosition() {
if(currentState == State.WALKING) {
isColliding = false;
cm.checkTile(this);
if(!isColliding) {
switch(currentDirection) {
case UP -> worldY -= speed;
case DOWN -> worldY += speed;
case LEFT -> worldX -= speed;
case RIGHT -> worldX += speed;
}
}
}
}
I’m working on a 2D Top-Down RPG and facing an issue with my collision detection. I have two classes: Entity.java and CollisionManager.java.
The Entity class contains attributes like speed and a BoundingBox (represented by a Rectangle object). Before moving the entity, I call a method from the CollisionManager class to check for collisions with the tiles.
The problem is that when I increase the entity’s speed, the collision is detected too early, a few pixels before the entity actually reaches the tile.
CollisionManager.java (checkTile method):
public void checkTile(Entity entity) {
int entityLeftWorldX = entity.worldX + entity.boundingBox.x;
int entityRightWorldX = entityLeftWorldX + entity.boundingBox.width; // Cambiato per maggiore chiarezza
int entityTopWorldY = entity.worldY + entity.boundingBox.y;
int entityBottomWorldY = entityTopWorldY + entity.boundingBox.height; // Cambiato per maggiore chiarezza
int entityLeftColumn = entityLeftWorldX / wm.TILE_SIZE;
int entityRightColumn = entityRightWorldX / wm.TILE_SIZE;
int entityTopRow = entityTopWorldY / wm.TILE_SIZE;
int entityBottomRow = entityBottomWorldY / wm.TILE_SIZE;
switch (entity.currentDirection) {
case UP -> entityTopRow = (entityTopWorldY - entity.speed) / wm.TILE_SIZE;
case DOWN -> entityBottomRow = (entityBottomWorldY + entity.speed) / wm.TILE_SIZE;
case LEFT -> entityLeftColumn = (entityLeftWorldX - entity.speed) / wm.TILE_SIZE;
case RIGHT -> entityRightColumn = (entityRightWorldX + entity.speed) / wm.TILE_SIZE;
}
int[] topTiles = {
wm.firstLayerMap.GAME_MAP[entityLeftColumn][entityTopRow],
wm.firstLayerMap.GAME_MAP[entityRightColumn][entityTopRow]
};
int[] bottomTiles = {
wm.firstLayerMap.GAME_MAP[entityLeftColumn][entityBottomRow],
wm.firstLayerMap.GAME_MAP[entityRightColumn][entityBottomRow]
};
if (isTileColliding(topTiles) || isTileColliding(bottomTiles)) {
entity.isColliding = true;
}
}
private boolean isTileColliding(int... tileNums) {
for (int tileNum : tileNums) {
if (tileNum >= 0 && isTileSolid(tileNum, wm.firstLayerMap)) {
return true;
}
}
return false;
}
private boolean isTileSolid(int tileNum, TileManager layer) {
return layer != null && layer.tileMap.get(tileNum) != null && layer.tileMap.get(tileNum).isSolid;
}
Call to the method in Entity.java:
private void updatePosition() {
if(currentState == State.WALKING) {
isColliding = false;
cm.checkTile(this);
if(!isColliding) {
switch(currentDirection) {
case UP -> worldY -= speed;
case DOWN -> worldY += speed;
case LEFT -> worldX -= speed;
case RIGHT -> worldX += speed;
}
}
}
}
Share
Improve this question
edited Nov 18, 2024 at 17:59
Luca Facchini
asked Nov 18, 2024 at 17:48
Luca FacchiniLuca Facchini
374 bronze badges
5
|
1 Answer
Reset to default 0The problem is that the character doesn't move if the collision is detected; instead, its position should be adjusted just enough to not make it clip into the tiles.
if (isTileColliding(topTiles) || isTileColliding(bottomTiles))
after you already moved the positions in your Entity, you should do that before moving? – Je Campos Commented Nov 18, 2024 at 18:47java.awt.Rectangle
class has anintersects
method. – Gilbert Le Blanc Commented Nov 18, 2024 at 20:29