XNA/Monogame:平台跳跃物理和对撞机问题

XNA/Monogame: Platformer Jumping Physics and Collider Issue

我有一个精灵,Player。我按以下方式更新 Player 的位置:

_position += (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;

其中 _position_direction_velocityVector2

我有一个简单的碰撞器 (BoxCollider),它根据碰撞器的位置和尺寸简单地生成一个矩形 (BoundingBox)。

Initialize() 中,我创建了一个新的 List<BoxCollider> 并用关卡的碰撞器填充它。

Update(),我将列表传递给 Player 以检查冲突。

碰撞检查方法:

public void CheckPlatformCollision(List<BoxCollider> colliders, GameTime gameTime)
{
    var nextPosition = _position + (_direction * _velocity) * (float)gameTime.ElapsedGameTime.TotalSeconds;
    Rectangle playerCollider = new Rectangle((int)nextPosition.X, (int)nextPosition.Y, BoundingBox.Width, BoundingBox.Height);
    foreach(BoxCollider collider in colliders)
    {
        if(playerCollider.Intersects(collider.BoundingBox))
        {
            nextPosition = _position;
        }
    }
    Position = nextPosition;
}

现在,我尝试实现重力的所有方法都失败了。如果 Player 从太高的地方掉落,nextPosition 会变得离 Player 太远并使其卡在半空中。

我也遇到了水平碰撞问题,问题很相似:Player 停止得太快,中间有一个 space。有时我 Player 坚持对撞机的一侧。

我想知道的是:

如何使用 _position_direction_velocity 正确实施重力和跳跃?如何正确处理水平和垂直方向的碰撞?

对于重力,在更新之前添加这个 _position:

_velocity += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds;

其中 gravity 类似于 new Vector2(0, 10)


对于跳跃,需要设置玩家按下跳跃键时速度的垂直分量:

if (jumpPressed && jumpAvailable)
{
    _velocity.Y = -10; // Numbers are example. You need to adjust this
    jumpAvailable = false;
}

当玩家触地时,您需要重置 jumpAvailable


碰撞是一件非常复杂的事情。但是如果你在互联网上寻找 "XNA implement collision" 你会找到很多答案。

方法有很多种。其中之一是将玩家推回 boxcollider 的边界,而不是像您在代码中所做的那样不让他移动。代码将是:

if (IntersectsFromTop(playerCollider, collider.BoundingBox))
{
    _position.Y = collider.BoundingBox.Y - BoundingBox.Height;
}
else if (IntersectsFromRight(playerCollider, collider.BoundingBox))
{
    _position.X = collider.BoundingBox.X + collider.BoundingBox.Width;
}
// And so on...

辅助方法可以像这样实现:

private static bool IntersectsFromTop(Rectange player, Rectangle target)
{
    var intersection = Rectangle.Intersect(player, target);
    return player.Intersects(target) && intersection.Y == target.Y && intersection.Width >= intersection.Height;
}

private static bool IntersectsFromRight(Rectange player, Rectangle target)
{
    var intersection = Rectangle.Intersect(player, target);
    return player.Intersects(target) && intersection.X + intersection.Width == target.X + target.Width && intersection.Width <= intersection.Height;
}
// And so on...

可以用图片解释该代码背后的基本原理:

图中widthheight对应路口,紫色。