3

我正在尝试实现一个简单的 AABB 系统,其中边界框从玩家的最后一个位置和下一个位置获取玩家的边界框。应该修改下一个边界框以防止任何非法移动(即穿过墙壁)。

目前,我的代码在一定程度上有效。例如,当我只向一个方向移动(键盘控制)时,我会停在正确的点:

碰撞截图

请注意,白色方块是实际的边界框,红色边框是专有的右下角坐标(因此红线进入地形内部是正确的)。

真正的问题出现在尝试同时移动两个轴时。例如,每当我在拥抱顶墙时向左移动(按住W),玩家就会以 16*16 的固定间隔卡住(在每个瓷砖的边缘)。一旦我解决了这个问题,我将创建某种贪心算法来对边界框进行分组,但目前BoundingBox地图中每个填充的图块只有一个:int i, j; boxes.add(new BoundingBox(new Vec2(i = x * 16, j = y * 16), new Vec2(i + 16, j + 16)));在 GIF 中显示正在发生的事情可能更容易:

解释碰撞卡住的 GIF

为每个边界框调用该collide函数,其中包含玩家的最后一个位置和最后一个框的修改位置,从左上角开始并首先增加 X。这是边界框的代码:

public class BoundingBox {
    public Vec2 min, max;

    public BoundingBox(Vec2 min, Vec2 max) {
        this.min = min;
        this.max = max;
    }

    @Override
    public BoundingBox clone() {
        return new BoundingBox(new Vec2(this.min.x, this.min.y), new Vec2(this.max.x, this.max.y));
    }
    public BoundingBox offset(Vec2 vec) {
        this.min.x += vec.x;
        this.max.x += vec.x;
        this.min.y += vec.y;
        this.max.y += vec.y;
        return this;
    }

    private boolean lineCollision(int leftA, int rightA, int leftB, int rightB) {
        return (leftA >= leftB && leftA < rightB) ||
            (rightA >= leftB && rightA < rightB);
    }

    public boolean collide(BoundingBox last, BoundingBox next) {
        boolean collided = false;

        if(lineCollision(last.min.y, last.max.y, this.min.y, this.max.y) || lineCollision(next.min.y, next.max.y, this.min.y, this.max.y)) {
            if(last.max.x <= this.min.x && next.max.x > this.min.x) { // Left -> Right
                next.offset(new Vec2(this.min.x - next.max.x, 0));
                collided = true;
            }
            if(last.min.x >= this.max.x && next.min.x < this.max.x) { // Right -> Left
                next.offset(new Vec2(this.max.x - next.min.x, 0));
                collided = true;
            }
        }
        if(lineCollision(last.min.x, last.max.x, this.min.x, this.max.x) || lineCollision(next.min.x, next.max.x, this.min.x, this.max.x)) {
            if(last.max.y <= this.min.y && next.max.y > this.min.y) { // Top -> Bottom
                next.offset(new Vec2(0, this.min.y - next.max.y));
                collided = true;
            }
            if(last.min.y >= this.max.y && next.min.y < this.max.y) { // Bottom -> Top
                next.offset(new Vec2(0, this.max.y - next.min.y));
                collided = true;
            }
        }
        return collided;
    }
}

也许这个问题与操作顺序有关?这似乎不太可能,但似乎颠倒两个if语句的顺序会collide改变行为 - 我卡住的墙壁发生了变化。

据我所知,第一次发生碰撞时,合成向量应该在墙外,所以它不再碰撞 - 对吧?这里一定有某种逻辑错误,但我自己无法发现。

根据要求,此 pastebin 中提供了额外代码:http: //pastebin.com/ueBAKJ9C

4

0 回答 0