如何修复3D AABB碰撞在角上无法正常工作

时间:2018-12-31 20:21:34

标签: c# collision-detection collision aabb

我目前正在开发《我的世界》副本,现在正尝试实现玩家到地形的碰撞。我的方法是通过以速度扩展的玩家的碰撞盒获得玩家可能与之碰撞的块,然后通过将沿每个轴的距离与该方向上的速度进行比较并保持较小的距离,来处理每个块。然后,最后,我将播放器沿每个轴最小移动。

现在我现在遇到的问题是,当移动到积木的角落或边缘时,它无法按预期工作(否则会发生),而是使玩家在积木内部四处转瞬即逝,甚至让他完全走动进入块。我该如何解决?

Player.cs(更新方法):

IList<Box> collidables = world.GetBoxes(collisionBox.Moved(position).Expanded(velocity * 2));

foreach (Box c in collidables) {
    velocity = collisionBox.Moved(position).ResolveCollision(c, velocity);
}

position += velocity;

Box.cs(在struct Box内部):

public Box Expanded(Vector3 expand) {
    Vector3 _min = min;
    Vector3 _max = max;

    if (expand.X < 0) {
        _min.X += expand.X;
    } else {
        _max.X += expand.X;
    }

    if (expand.Y < 0) {
        _min.Y += expand.Y;
    } else {
        _max.Y += expand.Y;
    }

    if (expand.Z < 0) {
        _min.Z += expand.Z;
    } else {
        _max.Z += expand.Z;
    }

    return new Box(_min, _max);
}

public float ResolveXCollision(Box b, float x) {
    if (b.Max.Y <= Min.Y || b.Min.Y >= Max.Y) {
        return x;
    }

    if (b.Max.Z <= Min.Z || b.Min.Z >= Max.Z) {
        return x;
    }

    if ((x > 0) && (Center.X <= b.Center.X)) {
        float max = b.Min.X - Max.X;
        if (Math.Abs(max) < Math.Abs(x)) {
            x = max;
        }
    }

    if ((x < 0) && (Center.X >= b.Center.X)) {
        float max = b.Max.X - Min.X;
        if (Math.Abs(max) < Math.Abs(x)) {
            x = max;
        }
    }

    return x;
}

public float ResolveYCollision(Box b, float y) {
    if (b.Max.X <= Min.X || b.Min.X >= Max.X) {
        return y;
    }

    if (b.Max.Z <= Min.Z || b.Min.Z >= Max.Z) {
        return y;
    }

    if ((y > 0) && (Center.Y <= b.Center.Y)) {
        float max = b.Min.Y - Max.Y;
        if (Math.Abs(max) < Math.Abs(y)) {
            y = max;
        }
    }

    if ((y < 0) && (Center.Y >= b.Center.Y)) {
        float max = b.Max.Y - Min.Y;
        if (Math.Abs(max) < Math.Abs(y)) {
            y = max;
        }
    }

    return y;
}

public float ResolveZCollision(Box b, float z) {
    if (b.Max.X <= Min.X || b.Min.X >= Max.X) {
        return z;
    }

    if (b.Max.Y <= Min.Y || b.Min.Y >= Max.Y) {
        return z;
    }

    if ((z > 0) && (Center.Z <= b.Center.Z)) {
        float max = b.Min.Z - Max.Z;
        if (Math.Abs(max) < Math.Abs(z)) {
            z = max;
        }
    }

    if ((z < 0) && (Center.Z >= b.Center.Z)) {
        float max = b.Max.Z - Min.Z;
        if (Math.Abs(max) < Math.Abs(z)) {
            z = max;
        }
    }

    return z;
}

public Vector3 ResolveCollision(Box b, Vector3 mov) {
    float x = ResolveXCollision(b, mov.X);
    Box xb = b.Moved(new Vector3(x, 0, 0));

    float y = ResolveYCollision(xb, mov.Y);
    Box yb = xb.Moved(new Vector3(0, y, 0));

    float z = ResolveZCollision(yb, mov.Z);
    Box zb = yb.Moved(new Vector3(0, 0, z));

    return new Vector3(x, y, z);
}

public Box Moved(Vector3 movement) => new Box(min + movement, max + movement);

0 个答案:

没有答案