Monogame基本碰撞检测无法工作

时间:2016-12-20 05:30:03

标签: c# 2d monogame side-scroller

在检测基本碰撞方面我有一个奇怪的问题,坦率地说,我无法弄清楚原因。

所以我的播放器运动在我的Player.cs类中,并且在这个类中包含一个Update()方法,该方法在Game1.cs的主游戏循环中调用。 我把它设置好,以便当我的播放器的击中框' 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类中,一个SpriteTile对象只存储2个东西,一个Texture2D,以及一个在我从Tiled Collision Layer加载碰撞时预先确定的Position。

然而,Bounds Method只返回一个显示当前图块边界的矩形。它的定义如下:

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

关于这一切的令人费解的部分是当我添加简单的调试代码将这些值绘制到屏幕上,并测试碰撞是否有效时,我得到了这个:

enter image description here

根据我绘制的边界框,它应该相交,因此停止下降。即使我得到了碰撞响应代码错误,布尔' inAir'应该设置为true。 (是的,因为字符串被绘制到屏幕上,如下所示:"正在相交:" +!Player.inAir意味着如果要进行交叉,它将绘制到屏幕为真。

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

如果有人能帮我弄清楚这个简单的想法在哪里出错,我会更感激不尽!谢谢你们。

1 个答案:

答案 0 :(得分:1)

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

让我们说gameMap.CollisionSprites包含2个精灵。与之相交的第一个精灵。第二个你没有。在循环的第一次传递HitBox.Intersects(t.Bounds)为真,导致inAir按预期设置为false。但是,循环没有结束,HitBox.Intersects(t.Bounds)在第二个精灵上运行,这是假的,并将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));

您可能遇到其他问题,但这可以解决我可以收集的碰撞问题。