【问题标题】:Java Tile Game - Collision DetectionJava Tile Game - 碰撞检测
【发布时间】:2012-04-29 15:13:41
【问题描述】:

我正在使用图块制作 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;
          } 
    }
}

任何帮助将不胜感激

谢谢

【问题讨论】:

    标签: java collision-detection tile


    【解决方案1】:

    为您的角色保留两个位置 - 它所在的位置(如上一帧、移动等),以及您想要移动它的位置。然后仅在未检测到碰撞时才移动它 - 如果您不允许损坏状态,则不必修复它。

    编辑:collision 方法应该是 boolean - 它应该在实际移动角色之前完成,例如

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

    Edit2: 前面的只能是一小步,如果需要局部移动,你真的需要知道角色的原始位置,比如move(originalPosition, desiredPosition, tile),在那里你可以推断出方向来自originalPositiontile

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

    【讨论】:

    • 这会导致奇怪的情况,具体取决于时间步长间隔。
    • @Matzi 不是真的,在执行某些用户命令之前进行验证 - 如果它没有验证,您可以进行自定义处理。
    • @KirilRaychev 我不太明白你想说什么
    • @grimrader22 我尽量把它说得更清楚一些,请问是否还不够好。
    • @KirilRaychev 从个人经验来看,情况并非如此。 :) 如果步长很小,它可以有小的 evvect,但问题是存在的。
    【解决方案2】:

    首先,任何Sprite(这里的角色和图块)都应该有四个成员:xPos、yPos、xVec、yVec。考虑到这一点,您就知道角色在哪里以及下一帧将在哪里。

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

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

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

    【讨论】:

    • xVec 和 yVec 变量代表什么?
    • 对不起,我不是很清楚,这些是精灵的方向向量(你也可以使用 Vector2f 或 Point2D)。该值可以解释为精灵在每个方向上的速度。因此,如果角色正好从左侧击中瓷砖,xVec 为正值,yVec 为 0;命中后,xVec 应该具有相同的值,但现在为负值。如果您需要更多帮助,请告诉我。
    • 我不太明白你在说什么,对不起,如果我是愚蠢的。 xand y Vecs 会是速度吗?
    • 对。假设精灵在 xPos = 10,yPos = 20,xVec = 3,yVec = 2。所以,在下一帧中,xPos 将为 13,yPos 将为 22。之后,xVec 和 yVec 可能相同(a太空船)、减少(摩擦、重力等)或增加(油门)。在发生碰撞的情况下,xVec 和 yVec 将根据另一个精灵的位置而改变。回到这个例子,如果角色的 xVec 为 3,yVec 为 1,并且从左侧命中(character.xPos
    【解决方案3】:

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

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

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

    3. 现在可以比较 Rx,Ry,Sx,Sy 来判断 Rx 和 Ry 的 Sx 和 Sy 在哪一侧

    4. 例如:

      if Sx < Rx then
        Sx = left side of Rx
      

    【讨论】:

      【解决方案4】:

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

          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,并且我的代码发生了变化,但这已经足够了。 在您的情况下,我建议将实体放在列表中,然后像我一样检查。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-01
        • 1970-01-01
        • 2013-01-31
        • 2011-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多