【问题标题】:Monogame Basic Collision Detection Fails to WorkMonogame 基本碰撞检测无法正常工作
【发布时间】:2016-12-20 05:30:02
【问题描述】:

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

所以我的玩家的移动在我的 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。

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

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

【问题讨论】:

    标签: c# 2d monogame side-scroller


    【解决方案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));
    

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

    【讨论】:

    • 哈哈,是的,完全正确。实际上,我在几个小时前在调试时搞砸了,它解决了这个问题!感谢您的帮助,如果其他人有类似的问题,很高兴将其留在这里以备将来使用!
    猜你喜欢
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多