您如何知道来自不同数组列表的两个元素是否发生冲突?

How do you know if two elements from different array lists collide?

现在,我们正在编写一款射击游戏,您可以在其中扮演一架飞机,其任务当然是射击敌人。我们有两种不同的 类,一种用于子弹,另一种用于敌人。我们在检查这两个元素是否相互碰撞时遇到了麻烦。

我们已经尝试比较这两个元素的 x 坐标和 y 坐标,但这似乎不起作用。

void hit() {
    for(int i = 0; i < Bullet.size(); i++) {
        Bullet bullet = (Bullet) Bullet.get(i);
        Enemy enemy = (Enemy) enemies.get(i);
        if(bullet.x < enemy.x + enemy.l 
           && enemy.x > enemy.x - enemy.l 
           && enemy.y < bul.y) {
            enemy.health -= 1;
            println("Hit");
            if(enemy.health <= 0) {
                enemy = null;
                // enemies.remove(i);
            }
        }      
    }
}

bul 是我们的子弹数组列表,enm 是敌人

问题是您在检查碰撞时只有一个 for-loop。所以你实际上是在检查子弹 #1 是否击中了敌人 #1。您将需要两个 for-loop 来检查每个子弹对付每个敌人。

void hit() {

    for(int i = 0; i < Bullet.size(); i++)
    {
        Bullet bul = (Bullet) Bullet.get(i);

        for(int j=0; j<enemies.size(); j++){
            Enemy enm = (Enemy)enemies.get(j);
            if(bul.x < enm.x + enm.l && bul.x > enm.x - enm.l && enm.y<bul.y)
            {
                enm.health -= 1;
                println("Hit");
                if(enm.health <= 0)
                {
                  enm = null;
                //  enemies.remove(i);
                }
            }  
        }
    }
}

你应该检查每一个敌人的每一颗子弹。在您的代码中,您正在检查第一个敌人的第一个子弹。

for(int i = 0; i < Bullet.size(); i++){
Bullet bul = (Bullet) Bullet.get(i);
for(int j=0;j<enemies.size();j++){
Enemy enm = (Enemy)enemies.get(j);
if(bul.x < enm.x + enm.l && bul.x > enm.x - enm.l && enm.y<bul.y)
{
enm.health -= 1;
println("Hit");
if(enm.health <= 0)
{
  enm = null;
//  enemies.remove(i);
}
}  
}    
}

ONE:我希望在某个地方找到敌人和子弹的列表。根据您的代码,我猜您已经在 Bullet class 中隐藏了 "bullets" 列表。我强烈建议您不要这样做。

二:您可能希望将碰撞测试放入其自己的方法中。你可以使用勾股定理得到两点的距离:(enemy.x - bullet.x)^2 + (enemy.y - bullet.y)^2 = 距离^2。我不知道你的 enm.l 属性 是什么,但它看起来有点像维度的东西。我在这里假设敌人的半径 属性:

boolean areColliding(final Enemy enemy, final Bullet bullet) {
  final int dX= enemy.x - bullet.x;
  final int dY= enemy.y - bullet.y;
  return (dX * dX) + (dY * dY) < e(enemy.radius * enemy.radius);
}

三:您的方法名为 "hit",但它没有 "hit" 任何内容。相反,它将碰撞的效果应用到敌人身上。名称应该反映这一点。在此示例中,我使用 iterator 遍历所有敌人,并使用 for-each-loop 遍历所有子弹。需要迭代器以便从基础列表中轻松删除当前元素:

void applyCollisions() {
  final Iterator<Enemy> enemyIterator = enemies.iterator();
  while (enemyIterator.hasNext()) {
    final Enemy eachEnemy = enemyIterator.next();

    for (final Bullet eachBullet : bullets) {
      if (areColliding(eachEnemy, eachBullet) {
        enemy.health--;
        println("Hit");
        if (enemy.health <= 0) {
          enemyIterator.remove();
        }
      }
    }
  }
}

您目前正在检查 Bullet(i) 与 Enemy(i),实际上只检查每颗子弹与一个敌人。 当敌人比子弹少时,我很惊讶这不会因为越界索引而崩溃。 正如其他答案已经说过的那样,通过两个循环来解决这个问题,这样你就可以检查每一个敌人的每一颗子弹。

我还想补充一点,您可以改进碰撞检测,目前您使用的是简单的边界框,这种边界框速度快,可能对您的游戏来说是可以接受的,但它本身很容易产生误报和误报底片。

就个人而言,我会添加另一个步骤 - 如果边界框碰撞显示命中,则委托给按位碰撞检测,基本上它可以通过为敌人和子弹设置和未设置像素的二维数组来工作。您将使用子弹和敌人的屏幕偏移量,并且在子弹的掩码中设置了一个位的地方,您检查敌人的位掩码以查看是否设置了该位,如果是,那么您就有了真正的碰撞。

显然,这将涉及另外 2 个循环并为您的精灵创建位掩码,但它会得到相当优化,因为初始边界框检查会丢弃很多不必要的检查。

如果可以的话,绝对值得实施,因为它使游戏更公平,事实上,只要子弹和敌人的速度是这样的,在游戏的一次更新中它们就不能在不击中的情况下相互穿过,然后它将是 100% 准确的。