Monogame 基本碰撞检测无法工作

Monogame Basic Collision Detection Fails to Work

我在检测基本碰撞时遇到了一个奇怪的问题,坦率地说,我不知道为什么。

所以我的玩家移动是在我的 Player.cs Class 中,在这个 class 中包含一个 Update() 方法,该方法在 [=39] 的主游戏循环中调用=]. 我设置了它,以便当我的玩家 'Rectangle Hitbox;' 的碰撞箱与碰撞块相交时,它将一个名为 'inAir' 的布尔值切换为 false。 当此布尔值为假时,重力应为零。 我的Player.cs的Update方法中的代码如下:

public void Update(GameTime gameTime) {

    //In my constructor for the Player class
    //Position is set equal to a new Vector2(0, 0)
    //Velocity is set equal to Vector2.Zero
    //Acceleration is set equal to a new Vector2(0, 100.0f);

    float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

    Velocity += Acceleration * deltaTime;
    Position += Velocity * deltaTime;

    HitBox = new Rectangle(new Point((int)Position.X, (int)Position.Y), new Point(Width, Height));

    foreach (SpriteTile t in gameMap.CollisionSprites) {
        if (HitBox.Intersects(t.Bounds))
            inAir = false;
        else if (!HitBox.Intersects(t.Bounds))
            inAir = true;
    }

    if (!inAir) {
        Velocity.Y = -Acceleration.Y * deltaTime;
    }

}

我还在屏幕上显示了一些简单的文本,告诉我布尔值 'inAir',稍后我提供的图像中将显示该值。

在我上面的 Player.cs class 中,SpriteTile 对象仅存储 2 个东西,一个 Texture2D 和一个在我从平铺碰撞层加载碰撞时预先确定的位置。

边界方法只是 returns 显示当前图块边界的矩形。定义如下:

public Rectangle Bounds {
    get {
        return new Rectangle(
            (int)Position.X,
            (int)Position.Y,
            Texture.Width,
            Texture.Height);
    }
}

这一切让我感到困惑的部分是,当我添加简单的调试代码以将这些值绘制到屏幕上并测试碰撞是否有效时,我得到了这个:

根据我绘制的边界框,它应该是相交的,因此停止了下降。即使我弄错了碰撞响应代码,布尔值 'inAir' 也应该设置为 true。 (是的,因为字符串是这样绘制到屏幕上的:"Is Intersecting: " + !Player.inAir 意思是如果发生交叉,它会绘制到屏幕上。

如果需要有关我的代码的更多信息,请告诉我,我将编辑 post 并提供。

如果有人能帮我弄清楚我在实施这么简单的想法时哪里出了问题,我将不胜感激!谢谢大家。

问题很可能是由于更新期间 "inAir" 的确定方式存在问题。在提供的循环下,只有 CollisionSprites 碰撞中的最后一个精灵才能触发 inAir 为 false。

假设 gameMap.CollisionSprites 包含 2 个精灵。您与之相交的第一个精灵。第二个你不知道。在循环的第一遍中,HitBox.Intersects(t.Bounds) 为 true,导致 inAir 如您所料设置为 false。但是,循环并没有结束,并且 HitBox.Intersects(t.Bounds) 在第二个精灵上是 运行,这是 false,并将 inAir 设置为 false。

有几种方法可以纠正这个问题。这是一种方法:

inAir = true; // assume you're in the air
foreach (SpriteTile t in gameMap.CollisionSprites) {
    if (HitBox.Intersects(t.Bounds))
    {
        inAir = false; 
        break; // you've collided, no reason to check any others
    }
}

使用 Linq 扩展方法进行了简化...

inAir = !gameMap.CollisionSprites.Any(t => HitBox.Intersects(t.Bounds));

您可能遇到了其他问题,但根据我收集到的信息,这应该可以解决您的碰撞检测问题。