简体   繁体   中英

Java - Pixel-Perfect Collision - gap between player and wall

I'm currently working on a Top-Down-Shooter and having some issues with collision. My world is made of tiles (64x64). The tiles and the entities are rectangles. The player moves with a speed of eg 2.74 (and not in pixels for smoother movement). But when it comes to the collision between the player (an entity) and a wall i have some issues. To check if there is a collision i take the current position of my player and his movement speed to calculate where his next position would be and if there is any collision. But i check every pixel on the way, so i cant skip an obstacle even if the movement speed is very high. Let's just say the players current position is X:200 Y:200 and he moves 2.74 Pixels a tick in the x direction. My game now checks if there is any collision at X:201 Y:200, X:202 Y:200 or X:202.74 Y:200 and if not moves the player to that position. If I now try to move the player further in the x direction and there is a wall 0.26 Pixels away the player wont move and leave a tiny gap. I tried to calculate the distance between player and wall and add this amount to the players position but for that I need to know which side of the wall the player hits. Also I want the player to be able to move up and down when the wall he hits is in front of him and the other way around.

Here is my collision method (in Java):

public static boolean collision(float ex, float ey, int width, int height) { // ex, ey would be the next position of the player
    if (ex < 0 || ex + width > worldWidth || ey < 0 || ey + height > worldHeight) return true; // checks if this position is in the world
    int firstTileX = (int) (ex / Tile.TILE_SIZE); // calculates tiles he could possible collide width
    int firstTileY = (int) (ey / Tile.TILE_SIZE);
    int lastTileX = (int) ((ex + width - 1) / Tile.TILE_SIZE);
    int lastTileY = (int) ((ey + height - 1) / Tile.TILE_SIZE);
    for (int y = firstTileY; y <= lastTileY; y++) {
        if (y < 0) continue; // checks for out of bounds 
        if (y >= worldTileHeight) break;
        for (int x = firstTileX; x <= lastTileX; x++) {
            if (x < 0) continue;
            if (x >= worldTileWidth) break;
            if (tiles[y][x].solid) return true; // if the tile is solid -> collision found
        }
    }
    return false; // no collision found
}

And my movement method:

public void move(float xa, float ya) {
    float nx, ny;
    while (xa != 0 || ya != 0) {
        nx = x;
        ny = y;
        if (xa != 0) {
            if (Math.abs(xa) > 1) { // if the x-speed is greater than 1
                nx = x + MathUtil.abs(xa); // returns -1 for negative numbers and 1 for positiv
                xa -= MathUtil.abs(xa);
            } else { // less than 1
                nx = x + xa;
                xa = 0;
            }
        }
        if (ya != 0) { // same here
            if (Math.abs(ya) > 1) {
                ny = y + MathUtil.abs(ya);
                ya -= MathUtil.abs(ya);
            } else {
                ny = y + ya;
                ya = 0;
            }
        }
        if (!Level.collision(nx, ny, width, height)) setPosition(nx, ny); // checks if there is an collision and sets the new position if not
        else if (!Level.collision(nx, y, width, height)) x = nx; // if there was a collision check if the player can walk in x direction
        else if (!Level.collision(x, ny, width, height)) y = ny; // or in y direction
    }
}

My problem is the pretty much the same as CoderMusgrove's problem in his post ( Pixel-perfect collision and doubles ):

Summary & Question

I have a problem where if the speed of an entity isgreater thanthe distance from the tile it is going into, it will leave at least a pixel in between itself and the tile, and I really don't like this. What kind of algorithm could I use that will find the tiniest difference between the entity and the tile?

If you need any additional information, I will be glad to add it.

Thanks for your help!

Easily resolvable by changing your interpretation.

You are retaining a fractional position for the purpose of fine grained speed. Ignore the fraction for the purpose of collision detection and display (if you were to do sub-pixel rendering, do the collision on the subpixel rendering accurarcy level).

int screenX = (int) Math.round(objX);
int screenY = (int) Math.round(objY);
// rendering and collision detection based on rounded position

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM