Java平铺游戏 - 碰撞检测

时间:2012-04-29 15:13:41

标签: java collision-detection tile

我正在使用瓷砖制作java游戏。我遇到了碰撞元件的问题。我为地图上的每个图块定义矩形,为播放器定义另一个矩形。我遇到麻烦的是知道玩家在撞到矩形时从哪一边来,然后按照玩家来自的方向推动玩家。我已经创建了一个方法来检查矩形内部的字符数,因此它可以知道将其推出多少,但我无法弄清楚如何判断字符来自哪一方。

这是我当前的碰撞方法 - 注意,rect1是字符,rect2是瓷砖

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;
          } 
    }
}

非常感谢任何帮助

由于

4 个答案:

答案 0 :(得分:2)

为你的角色保留两个位置 - 它的位置(截至最后一帧,移动等),以及你想要移动它的位置。然后只有在你没有检测到碰撞时才移动它 - 如果你不允许腐败状态,你就不必修复它。

修改collision方法应为boolean - 应该实际移动角色之前完成,例如

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

编辑2:上一个只能用于一小步,如果你需要部分移动,你真的需要知道角色的原始位置,比如move(originalPosition, desiredPosition, tile),你可以推断来自originalPositiontile的方向。

重点是,在你有一个有效的位置之前,你实际上并没有移动角色。

答案 1 :(得分:1)

首先,任何精灵(此处的角色和图块)都应该有四个成员:xPos,yPos,xVec,yVec。考虑到这一点,你知道角色在哪里,并将在下一帧。

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

另外看看你的代码,你应该改进命题(例如,你在四个 if 语句中检查 if(rect1.intersects(rect2)) )。相反,只检查一次 intersects(),并检查每个可能的情况(左,右,顶部,底部命中)。

最后,碰撞方法应该接收2个精灵对象(例如, sprite1 sprite2 ),然后检查 intersects()方法,考虑两个精灵及其向量的原始位置。如果精灵在新位置相交,则相应地反转对象的向量。

答案 2 :(得分:1)

假设您可以检测到与代码的冲突。这是一种确定角色相对于矩形对象的位置的方法。

  1. 找到矩形的中间点。 (Rx,Ry)。

  2. 找到角色精灵的中间点。 (Sx,Sy)。

  3. 现在你可以比较Rx,Ry,Sx,Sy来确定哪一方是Sx和Rx的Rx和Ry

  4. 代表:

    if Sx < Rx then
      Sx = left side of Rx
    

答案 3 :(得分:1)

我自己也在苦苦挣扎,但经过一番思考后,可以通过将所有实体放入List中来完成此检查,在我的代码中我必须阻止玩家移动块。所有块都在List中。现在,当检查玩家位置时,我创建一个新的矩形并将玩家放置在向下一帧更新将发生的方向上向前一帧,如果矩形相交,那么该方向的更新将不会发生。以下是我的代码:

    if (isKeyPressed(KeyEvent.VK_LEFT)) {
        if(!collisionWithBlocks(1)){
            pl.x = pl.x - updatePlayerPosition;
        }
    }
    if (isKeyPressed(KeyEvent.VK_RIGHT)) {
        if(!collisionWithBlocks(0)){
            pl.x = pl.x + updatePlayerPosition;
        }
    }
    if (isKeyPressed(KeyEvent.VK_UP)) {
        if(!collisionWithBlocks(3)){
            pl.y = pl.y - updatePlayerPosition;
        }
    }
    if (isKeyPressed(KeyEvent.VK_DOWN)) {
        if(!collisionWithBlocks(2)){
            pl.y = pl.y + updatePlayerPosition;
        }
    }

collisionWithBlocks():

public boolean collisionWithBlocks(int side){
    for(Block b : main.blocks){
        Rectangle block = b.getBounds();
        Rectangle player = null;
        if(side == 0){
            player = new Rectangle(pl.x + updatePlayerPosition, pl.y, pl.getWidth(), pl.getHeight());
        } else if(side == 1){
            player = new Rectangle(pl.x - updatePlayerPosition, pl.y, pl.getWidth(), pl.getHeight());
        } else if(side == 2){
            player = new Rectangle(pl.x, pl.y + updatePlayerPosition, pl.getWidth(), pl.getHeight());
        } else if(side == 3){
            player = new Rectangle(pl.x, pl.y - updatePlayerPosition, pl.getWidth(), pl.getHeight());
        }

        if(player.intersects(block)){
            return true;
        }
    }

    return false;
}

updatePlayerPosition是2,并且我的代码发生了变化,但足够了。 在您的情况下,我建议将实体放入List中,然后像我一样检查。