0

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

所以我的玩家的动作在我的 Player.cs 类中,并且在这个类中包含一个 Update() 方法,该方法在我的 Game1.cs 的主游戏循环中调用。我已将其设置为当我的播放器的命中框为“矩形命中框;”时 与碰撞瓷砖相交时,它将一个名为“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 类中,SpriteTile 对象仅存储 2 个东西,一个 Texture2D 和一个 Position,这是我从 Tiled Collision Layer 加载碰撞时预先确定的。

然而,Bounds 方法只是简单地返回一个显示当前图块边界的矩形。定义如下:

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

这一切对我来说令人费解的部分是当我添加简单的调试代码以将这些值绘制到屏幕上并测试碰撞是否正常工作时,我得到了这个:

在此处输入图像描述

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

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

如果有人能帮我弄清楚我在实现这样一个简单的想法时哪里出了问题,我将不胜感激!多谢你们。

4

1 回答 1

1

该问题很可能是由于在更新期间如何确定“inAir”的问题。在提供的循环下,只有 CollisionSprites 碰撞中的最后一个精灵可以触发 inAir 为假。

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

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

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));

您可能还会遇到其他问题,但这应该可以解决您的碰撞检测问题。

于 2016-12-21T03:19:56.657 回答