Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Tile Game - Collision Detection

I am making a java game using tiles. I am having trouble with the collision element. I am defining rectangles for each tile on the map, and another rectangle for the player. What I am having trouble with is knowing which side the player is coming from when it hits the rectangle, and then pushing the player off in the direction the player came from. I have already made a method that checks how much the character is inside the rectangle, so it can know how much to push it out, but I can't figure out how to tell which side the character is coming from.

here is my current collision methoe - note rect1 is the character and rect2 is the tile

public void collision(Rectangle rect1, Rectangle rect2) {
    float xAdd;
    float xAdd2;
    float yAdd;
    float yAdd2;

    boolean hitRight = false;
    boolean hitLeft = false;
    boolean hitTop = false;
    boolean hitBot = false;

    Vector2f rect1Origin = new Vector2f(rect1.x, rect1.y);
    Vector2f rect2Origin = new Vector2f(rect2.x, rect2.y);
    Vector2f rect1Mid = new Vector2f((rect1.x + rect1.width) / 2,(rect1.y + rect1.height) / 2);
    Vector2f rect2Mid = new Vector2f((rect2.x + rect2.width) / 2,(rect2.y + rect2.height) / 2);

    Vector2f rect1A = new Vector2f(rect1Origin.x + rect1.width, rect1.y);
    Vector2f rect1B = new Vector2f(rect1Origin.x, rect1Origin.y+ rect1.height);
    Vector2f rect1C = new Vector2f(rect1Origin.x + rect1.width,rect1Origin.y + rect1.height);

    Vector2f rect2A = new Vector2f(rect2Origin.x + rect2.width, rect2.y);
    Vector2f rect2B = new Vector2f(rect2Origin.x, rect2Origin.y
            + rect2.height);
    Vector2f rect2C = new Vector2f(rect2Origin.x + rect2.width,
            rect2Origin.y + rect2.height);

    xAdd = rect2C.x - rect1B.x;
    xAdd2 = rect1C.x - rect2B.x;

    yAdd = rect2A.y - rect1B.y;
    yAdd2 = rect2C.y - rect1A.y;


    if (rect1Mid.y < rect2Mid.y) {
        if (rect1.intersects(rect2)) {
            y_pos += yAdd;
        }
    }
    if (rect1Mid.y > rect2Mid.y) {
        if (rect1.intersects(rect2)) {
            System.out.println(yAdd2);
            y_pos += yAdd2;
        }

    }
    if(rect1Mid.x > rect2Mid.x){
        if(rect1.intersects(rect2)){
            hitRight = true; x_pos += xAdd;
        }
    } 
    if(rect1Mid.x< rect2Mid.x){ 
          if(rect1.intersects(rect2)) {
              x_pos += -xAdd2;
          } 
    }
}

Any help would be greatly appreciated

Thanks

like image 600
Matthew Tory Avatar asked Apr 29 '12 15:04

Matthew Tory


2 Answers

Keep two positions for your character - where the it is (as of last frame, move, etc.), and where you want to move it. Then only move it if you don't detect collision - if you don't allow for corrupt state, you don't have to fix it.

Edit: The collision method should be boolean - it should be done before actually moving the character, like

if (!collision(character, tile))
{
    doMove(character);
}
else
{
    //custom handling if required
}

Edit2: The previous would work only for a small step, if you need a partial move, you really need to know the character's original position, like move(originalPosition, desiredPosition, tile), where you can deduce the direction from the originalPosition and the tile.

The main point is, you don't actually move the character, before you have a valid position for it.

like image 156
jmruc Avatar answered Sep 24 '22 21:09

jmruc


First of all, any Sprite (the character and the tile here) should have four members: xPos, yPos, xVec, yVec. With that in mind, you know where the character was and will be in the next frame.

sprite.xPos += sprite.xVec;
sprite.yPos += sprite.yVec;

Also take a look at your code, you should improve the propositions (for instance, you check if(rect1.intersects(rect2)) in the four if statements). Instead, check only once for the intersects(), and inside check for each possible case (left, right, top, bottom hit).

Finally, the collision method should receive 2 sprites objects (for instance, sprite1 and sprite2), and then check for the intersects() method, taking into account the original positions of both sprites and its vectors. If the sprites intersect in the new position, then you invert the object's vector accordingly.

like image 45
Federico Cristina Avatar answered Sep 22 '22 21:09

Federico Cristina