【问题标题】:Collision Code isn't working, despite several checks [closed]尽管进行了多次检查,但碰撞代码仍无法正常工作[关闭]
【发布时间】:2013-07-28 01:22:48
【问题描述】:

我正在研究 XNA 中的碰撞。出于某种原因,尽管我尝试了很多次,但它不起作用。如果我触摸它,它将起作用。但有时它会随机停止运行,就好像发生了碰撞一样。它的工作方式是有五十个 20 x 20 像素的正方形。如果您的方格以任何方式触及另一个方格,则游戏结束。

checkcollision()
    {
        for (int i = 0; i < 50; i++)
        {
            if ((loc.X + me.Width > enemyloc[i].X) && (loc.Y + me.Height > enemyloc[i].Y) && (loc.Y < enemyloc[i].Y) && (loc.X < enemyloc[i].X)) { return true; }
            if ((loc.X > enemyloc[i].X) && (enemyloc[i].X + enemy[i].Width > loc.X) && (loc.Y + me.Height > enemyloc[i].Y) && (loc.Y < enemyloc[i].Y)) { return true; }
            if ((loc.X > enemyloc[i].X) && (loc.X < enemyloc[i].X + enemy[i].Width) && (loc.Y > enemyloc[i].Y) && (loc.Y < enemyloc[i].Y + enemy[i].Height)) { return true; }
            if ((loc.X < enemyloc[i].X) && (loc.X + me.Width > enemyloc[i].X) && (loc.Y < enemyloc[i].Y) && (loc.Y < enemyloc[i].Y + enemy[i].Height)) { return true; }
        }
        return false;
    }

【问题讨论】:

  • 尝试使用调试器。

标签: c# xna collision


【解决方案1】:

我同意这段代码看起来有点太复杂了。我建议将你的敌人和玩家碰撞箱存储为Rectangle struct 的实例。 Rectangle 结构体提供了一个名为Contains 的方法,其定义为:

public bool Contains(int x, int y);

如果定义在 x 和 y 的点存在于矩形中,此方法将返回 true。因此使用这个结构,代码会变得更简单:

public bool checkcollision(Rectangle player)
{
    for (int i = 0; i < enemy.Length; i++)
    {
        if (enemy[i].Contains(player.Left, player.Top)
            || enemy[i].Contains(player.Right, player.Top)
            || enemy[i].Contains(player.Left, player.Bottom)
            || enemy[i].Contains(player.Right, player.Bottom))
        {
            return true;
        }
    }
    return false;
}

【讨论】:

  • 谢谢,这真的很有帮助
  • 欢迎您。如果你有时间,你能把我的答案标记为正确吗?谢谢。
  • 感谢您将答案标记为已接受。
【解决方案2】:

正如我在评论中所说,阅读起来太难了。虽然我不会声称这是 问题(使用 Mitch Wheat 建议的调试器),但它肯定可以解决!

首先,让我们概述一个单轴 X 的碰撞检测。我们先不寻找碰撞,而是寻找无碰撞没有沿 X 轴发生碰撞[仅]当“(玩家到敌人左侧)或(敌人到玩家左侧)”时。 (原因是,如果这些都不正确,那么“玩家对敌”一定是正确的 - 如果需要,请使用图片。)

设 p = 玩家,e = 敌人,则没有碰撞 [仅] 当 (p.X + p.W 存在冲突!

因此我们可以编写碰撞方法

bool Collides (IEntityBox p, IEntityBox e) {
    bool noCollisionX = (p.X + p.W < e.X) || (e.X + e.W < p.X);
    bool collisionX = !noCollisionX;
    bool noCollisionY = (p.Y + p.H < e.Y) || (e.Y + e.H < p.Y);
    bool collisionY = !noCollisionY;
    // not that the collision on BOTH axises must be fulfilled
    return collisionX && collisionY;
 }

笔记(留作练习):

  1. IEntityBox 具有 X/Y 和 W/H 属性,并且假定 (0,0) 位于屏幕的左上角。为您的实现使用正确的类型/属性。如果玩家和其他实体的定位是统一的,那就更简单了。

  2. 可以重写表达式(并且可以应用 De Morgan 的)以稍微清理一下。简单的折叠将消除所有变量,同时保持“易于”阅读。

  3. 如果 noCollisionX(这意味着 !collisionX)为真,我们不需要计算 noCollisionY。如果折叠,这可以使用 if/else 或短路评估。

用法同样被清理:

bool PlayerCollidesWithAnyEnemy () {
  foreach (var e in enemies) { // avoid hard-coding numbers
    if (Collides(player, e)) {
      return true;
    }
  }
  return false;
}
// ..
var playerOopsed = PlayerCollidesWithAnyEnemy();

或者,使用 LINQ:

var playerOopsed = enemies.Any(e => Collides(player, e));

【讨论】:

    猜你喜欢
    • 2011-07-25
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多