最新消息:Welcome to the puzzle paradise for programmers! Here, a well-designed puzzle awaits you. From code logic puzzles to algorithmic challenges, each level is closely centered on the programmer's expertise and skills. Whether you're a novice programmer or an experienced tech guru, you'll find your own challenges on this site. In the process of solving puzzles, you can not only exercise your thinking skills, but also deepen your understanding and application of programming knowledge. Come to start this puzzle journey full of wisdom and challenges, with many programmers to compete with each other and show your programming wisdom! Translated with DeepL.com (free version)

java - Collision detection issue with entity speed in 2D Top-Down RPG Game - Stack Overflow

matteradmin8PV0评论

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
  • 3 Hi there, please add your code in the body of your question, not through a link. Please check the How To Ask section. – Je Campos Commented Nov 18, 2024 at 17:53
  • Hello, sorry about that. Thanks :) I added it. – Luca Facchini Commented Nov 18, 2024 at 18:06
  • You are checking the 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:47
  • 1 Hello Luca, I think the problem is that you are using velocities greater than 1 px, so, if you have velocity = 5, and before moving you check if there is collision, you will not move and you will stay 5 px from the object, instead, if you check after moving, you will be superimposed to the object, therefore, use velocities equal or less than 1. – Marce Puente Commented Nov 18, 2024 at 20:17
  • The java.awt.Rectangle class has an intersects method. – Gilbert Le Blanc Commented Nov 18, 2024 at 20:29
Add a comment  | 

1 Answer 1

Reset to default 0

The 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.

Post a comment

comment list (0)

  1. No comments so far