1
votes

In my game, the player navigates a maze. I can't figure out how to do proper collision detection with the walls. It is easy to do collision detection for staying in a certain area:

if (x > rightWallX - playerWidth) x = rightWallX - playerWidth;
if (x < leftWallX) x = leftWallX;
//...

But how would I do collision detection for many walls?

I can do plain collision detection without correction (like if (intersecting) return true;), but I can't correct this correctly. If I just store the old x and y and reset them, then

  1. The object never actually touches the wall
  2. If the object can go up but is blocked to the right, it won't go up, it will just not move.

How is collision detection in a maze done?

3
"I can do plain collision detection without correction" great idea; now add the correction. "store the old x and y and reset them" c'mon, you can do better :-)John Dvorak
@JanDvorak what else would I do? I can't think of any other way :/tckmn
Suggestion #1: In most cases it suffices to reset either x or y.John Dvorak
@JanDvorak But then the object never actually touches the wall, it hovers a couple pixels away. (that's because the object doesn't move just 1 pixel per tick)tckmn
Suggestion #2: you don't need to reset the value. It suffices to change it enough.John Dvorak

3 Answers

1
votes

The easiest way, once you have solved collision detection, to fix the collision is to move the actor to the closest valid position to where the actor would be were it not for the object it collides with. This assumes no inertia, but it is sufficient for maze-like games or top-down map-crawling games.

If you want to simplify your calculations further, you can limit yourself to detecting if changing the actor's x or y coordinate would be better. If your actor has an axis-aligned rectangular hit-box and all obstacles are axis-aligned rectangular as well (the simplest case), this assumption is indeed correct. However, the results might not be satisfactory in some other cases (potential artifact: speed boost from gliding diagonal walls - not the case in most maze games).

Keep in mind multiple collisions could happen concurrently (pushing against two walls). If there are no sharp angles between two walls that an actor could both intersect (say, if all your obstacles are axis aligned and sufficiently spaced), fixing each collision in turn will suffice - just don't stop after the first collision.

1
votes

You can use Rectangle.intersects() method:

    public Rectangle Player(){
         return new Rectangle(PlayerX,PlayerY,PlayerWidth,PlayerHeight);
         //we do this for getting players x and y values every tick
    }

    if(Player().intersects(new Rectangle(0,0,100,50)))//if(player touching wall)

new Rectangle(0,0,100,50) is just an example you can change it.

0
votes

Ok so i'm currently making a 2D top down view game and I'm not sure how you created your maze. However, in my game my Level is created from a Tile[][] tiles = new Tile[levelWidth][levelHeight]; array. The way i handled collision detection was by checking the surrounding tiles to see if they were solid.

This is my getTile method.

public Tile[][] getTile(int x, int y) {
    if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
    return new VoidTile();
} else {
    return tiles[x][y];
}
}

In my Tile.java class i have a isSolid() method which returns whether the tile is solid or not. All of my tiles extend my Tile.java so they inherit this method and I override it in their constructor. As i said previously, I am not sure whether or not you use the same style of level implementation as i do. However, It is good practice to do it this way :)

Personally, I am not a big fan of using the .intersects() and .contains() methods for Sprite collision detection. I mainly use them for buttons and alike.

Ok so, In my player.java class i have a checkBlockedDirection(int x, int y) method and it looks like this.

    public void checkBlockedDirection(int x, int y) {
    boolean u = map.getTile(x, y - 1).isSolid();
    boolean d = map.getTile(x, y + 1).isSolid();
    boolean l = map.getTile(x - 1, y).isSolid();
    boolean r = map.getTile(x + 1, y).isSolid();

    if (u) {
        uBlocked = true;
        System.out.println("up tile blocked");
    } else {
        uBlocked = false;
    }
    if (d) {
        dBlocked = true;
        System.out.println("down tile blocked");
    } else {
        dBlocked = false;
    }
    if (l) {
        lBlocked = true;
        System.out.println("left tile blocked");
    } else {
        lBlocked = false;
    }
    if (r) {
        rBlocked = true;
        System.out.println("right tile blocked");
    } else {
        rBlocked = false;
    }
}

Then in my player update method i have this

public void tick() {
    float dx = 0;
    float dy = 0;

    if (input.up.isPressed()) {
        direction = 0;
    } else if (input.down.isPressed()) {
        direction = 2;
    } else if (input.left.isPressed()) {
        direction = 3;
    } else if (input.right.isPressed()) {
        direction = 1;
    } else {
        direction = 4; // standing
    }

    checkBlockedDirection((int)x, (int)y);


    if (input.up.isPressed() && y > 0 && !uBlocked) {
            dy += -speed;
    } else if (input.down.isPressed() && y < map.getHeight() - 1 && !dBlocked) {
            dy += speed;
    } else if (input.left.isPressed() && x > 0 && !lBlocked) {
            dx += -speed;
    } else if (input.right.isPressed() && x < map.getWidth() - 1 && !rBlocked) {
            dx += speed;
    }
    x += dx;
    y += dy;

}

Basically it just checks whether or not the blocks up, down, left, or right are solid. If they are solid then it wont move and if they arent solid then you can move in the desired direction.

Not sure if this helps or not but it's just my take on this kind of grid collision detection :)

Hope this helps :)

Enjoy