【问题标题】:Tile based collision detection, object falls through tiles基于瓦片的碰撞检测,物体从瓦片中落下
【发布时间】:2014-03-05 05:58:39
【问题描述】:

我在以较低帧速率在基于图块的级别上进行碰撞检测时遇到问题。我有一个带有 LibGdx 游戏引擎的 Java 平台游戏。在 60 帧速率下,游戏运行良好,但如果我尝试以 30 FPS 的速度运行,角色从跳跃中落下时会穿过瓷砖。

我发现角色移动得太快了。我已经添加了一些东西来检查角色是否已经通过了任何瓷砖,请参阅 cmets 中的“// 1”到“// 1 end”。我不认为它真的有帮助,因为问题仍然存在。

当角色撞到瓷砖的角落时,似乎会从瓷砖上掉下来,虽然我不确定。它不会发生在平坦的地面上。这是问题的图片(左边是错误的,右边是应该的):

同样,问题只发生在较低的帧速率下。我不确定我必须在我的代码中更改什么。我的代码中缺少什么?还是我必须使用不同的算法?

这里是碰撞检测代码中最重要的部分。 collisionY 检查 y 轴上的碰撞,collisionX 在 x 轴上。 CheckTiles(checkX) 帮助查找应检查的图块(如果检查了 x 轴,则 checkX 为真,如果检查了假 y 轴):

protected boolean collisionY(Rectangle rect) {
    int[] bounds = checkTiles(false);
    Array<Rectangle> tiles = world.getTiles(bounds[0], bounds[1], bounds[2], bounds[3]);
    rect.y += velocity.y;
    if(velocity.y < 0 ) {
        grounded = false;
    }
    for (Rectangle tile : tiles) {
        if (rect.overlaps(tile)) {
            if (velocity.y > 0) {
                this.setY(tile.y - this.getHeight());
            }
            else {
                // 1 Check if there are tiles above
                Rectangle r = null;
                int i = 1;
                Rectangle r1 = null;
                do {
                    r1 = r;
                    r = world.getTile(tile.x, tile.y + i);
                    i++;
                } while (r != null);
                if(r1 != null) {
                    this.setY(r1.y + r1.height);
                }
                // 1 end
                else {
                    this.setY(tile.y + tile.height);
                }
                hitGround();
            }
            return true;
        }
    }
}

protected boolean collisionX(Rectangle rect) {
    int[] bounds = checkTiles(true);
    Array<Rectangle> tiles = world.getTiles(bounds[0], bounds[1], bounds[2], bounds[3]);
    rect.x += velocity.x;
    for (Rectangle tile : tiles) {
        if (rect.overlaps(tile)) {
            return true;
        }
    }
    return false;
}


protected int[] checkTiles(boolean checkX) {
    int startX, startY, endX, endY;
    if(checkX) {
        if (velocity.x > 0) {
            startX = endX = (int) (this.getX() + this.getWidth() + velocity.x);
        }
        else {
            startX = endX = (int) (this.getX() + velocity.x);
        }
        startY = (int) (this.getY());
        endY = (int) (this.getY() + this.getHeight());
    }
    else {
        if (velocity.y > 0) {
            startY = endY = (int) (this.getY() + this.getHeight() + velocity.y); //
        }
        else {
            startY = endY = (int) (this.getY() + velocity.y);
        }
        startX = (int) (this.getX());
        endX = (int) (this.getX() + this.getWidth());
    }
    return new int[]{startX, startY, endX, endY};
}

【问题讨论】:

  • 你从不使用增量值吗?它可以通过调用 Gdx.app.getDeltaTime() 来获得。此增量时间是一个浮点值,表示最后一帧渲染所花费的时间。这样,您可以确保实体的速度从一个系统到另一个系统是恒定的,而不是让速度快的计算机具有优势。
  • 是的,我使用它。不同FPS下速度是一样的。

标签: java libgdx collision-detection game-physics frame-rate


【解决方案1】:

只有在 A) rect.overlaps(tile)true 和 B) velocity.y &gt; 0false 时,才会运行“检查上面的图块”代码。我怀疑在你关心的情况下,这段代码根本没有被执行。角色要么没有与瓷砖重叠,因此不会发生上面的瓷砖检查,或者它的速度不是这样的检查发生。但是,我并不完全了解速度的工作原理(上下如何对应正负值?),我对这个游戏引擎也不熟悉。

不过,我会尝试不同的方法。我不会先移动角色(我认为rect.y += velocity.y; 就是这样做的),然后尝试检查它是否走得太远或穿过瓷砖,我会选择它移动的方向(velocity.y ) 并寻找 第一个会以这种方式命中的图块。如果有,则将角色放在该图块上。如果velocity.y 单位在该方向上没有任何阻碍,那么它将在这个时间片中移动整个距离。

【讨论】:

  • 负速度意味着向下,正向上。 'rect',是字符当前矩形的副本,所以当它改变时,实际位置不会改变。它仅用于碰撞检测。如果collisionX 返回false,则velocity.x 设置为0,与collisionY 相同。在碰撞检测方法之后设置字符的位置。
  • 啊,我明白了。我仍然认为通过向前看角色会撞到什么来进行碰撞检测可能会更好,如果有的话,而不是计算新的 y 并检查它是否发生了碰撞,但我可能错了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 2015-03-03
相关资源
最近更新 更多