-3

我正在研究 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;
    }
4

2 回答 2

2

我同意这段代码看起来有点太复杂了。我建议将您的敌人和玩家碰撞盒存储为Rectangle 结构的实例。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;
}
于 2013-07-28T01:56:39.173 回答
0

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

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

设 p = Player, e = Enemy,那么[仅] 当 (pX + pW < eX) || (eX + eW < pX)。这意味着在相反/否定的情况下存在碰撞

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

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));
于 2013-07-28T01:24:32.773 回答