我现在正在编写一个简单的游戏,我需要能够检测到许多对象之间的碰撞(检查10个对象是否与任何其他20个对象发生冲突,而不是在两个组之间发生碰撞)。我写了一些现在有效的简单代码但是在我检测到碰撞之后导致游戏速度极慢(顺便说一下,在Java中):
//Check for collisions between tanks and bullets
ArrayList<Object> objectsToRemove = new ArrayList<Object>();
for (int i = 0; i < tanksOnScreen.size(); i += 1) {
//Get tank
Tank tank = tanksOnScreen.get(i);
for (int e = 0; e < bulletsOnScreen.size(); e += 1) {
//Get bullet
Bullet bullet = bulletsOnScreen.get(e);
//Check for collision
if (tank.collides(bullet.x, bullet.y, 10, 10)) {
System.out.println("Collide");
objectsToRemove.add(bullet);
objectsToRemove.add(tank);
break;
}
}
}
for (Object obj:objectsToRemove) {
if (obj.getClass().equals(Bullet.class)) {
bulletsOnScreen.remove(bulletsOnScreen.indexOf(obj));
} else if (obj.getClass().equals(Tank.class)) {
tanksOnScreen.remove(tanksOnScreen.indexOf(obj));
}
}
坦克的collides()
方法:
public boolean collides(float px, float py, float pwidth, float pheight) {
// If the distance between the two centers of the lines on x and y axis
// Is less than the distance of half the w and h added together, the objects
// Are colliding
float x1 = (px > x) ? x : px, x2 = (px > x) ? px : x, y1 = (py > y) ? y : py, y2 = (py > y) ? py : y;
float w1 = (x1 < x2) ? width : pwidth, w2 = (x1 < x2) ? pwidth : width, h1 = (y1 < y2) ? height : pheight, h2 = (y1 < y2) ? pheight : height;
if ((x2 + w2/2) - (x1 + w1/2) < (w1/2 + w2/2)&&(y2 + h2/2) - (y1 + h1/2) < (h1/2 + h2/2)) {
return true;
} else {
return false;
}
}
我认为滞后是因为双for
循环,迭代对象。我不确定如何根除这些for循环或如何在屏幕的某个区域获取子弹,只检查这些子弹而不使用另一个for循环(我认为是隔离)。任何人都可以指出我正确的方向与许多物体碰撞检测?我不介意答案是什么语言,即使它是伪代码。
谢谢,
本
修改1
我现在正在使用Slick图形API for java,它为您提供了一个更新和渲染方法来添加渲染和游戏逻辑。我将此碰撞检测放在更新方法中(每帧调用一次 - 大约每秒60次)。碰撞发生后发生缓慢,并且从屏幕上移除对象 - 我觉得很奇怪。在删除for循环中的对象之后,可能break
命令会根除它吗?
修改2
感谢所有答案的人,这些参考资料对未来有很大的帮助。我只是通过交换子弹和坦克来解决问题,因此在子弹被摧毁后它没有继续循环。我不应该问这个问题,因为最后很容易解决。 Dave和Banthar说得对,问题不在于代码,它应该是即时的。
答案 0 :(得分:3)
一个好主意是使用octree。随着子弹的移动,我认为你需要一个动力学版本 - 互联网上有大量关于动力学数据结构的文章。
另外,如果你想检测更复杂的凸多边形之间的碰撞,我建议你使用gjk算法,这种算法非常快。请注意,这将仅加速一对对象的碰撞检测时间,对的数量仍将保持不变。
答案 1 :(得分:2)
除非我遗漏了某些东西,或者你没有显示其他代码,否则你在O(n ^ 2)中运行,其中n是20.这对用户来说应该是即时的。
尝试在调试器中逐步执行它,看看它在哪里放慢速度。
编辑以详细说明:您的昂贵操作不在您发布的代码中。它位于其他地方,由您发布的代码调用。
答案 2 :(得分:0)
感谢所有答案的人,这些参考资料对未来有很大的帮助。我只是通过交换子弹和坦克来解决问题,因此在子弹被摧毁后它没有继续循环。我不应该问这个问题,因为最后很容易解决。 Dave和Banthar表示问题不在于代码,并且它应该是即时的。