减少 hitTest 调用以提高 Flash 游戏性能的最佳实践

Best practice to cut down hitTest calls to improve performance of a flash game

我正在使用 Macromedia Flash 8 开发 Flash 游戏(它真的过时了,不是吗?)。玩家移动一架持续发射稳定子弹流的飞机,并用它来消灭敌人。很像气球超级猴子
我使用 MovieClip.hitTest() 方法来确定子弹是否与敌人相撞。然而,由于大量的子弹 (m) 和敌人 (n),它可能需要 O(mn) 次 hitTest() 调用,这非常慢。有没有什么方法可以通过减少 hitTest() 调用次数来提高游戏性能?
对于非 Flash 开发人员,假设 hitTest() 方法将两个形状作为输入,并且 returns 它们是否相互重叠。无论两个图的形状和大小如何,hitTest() 在 Θ(1) 时间内总是 returns。但是常量非常大,所以一次 hitTest() 调用花费的时间相当于数千次算术计算的时间。无需担心内存成本,因为总是有很多。

注意:所有这些东西都在快速移动,我只能保留它们的静态数组(即只能插入和删除,不能将元素从一个索引移动到另一个索引)。特定时间所有内容的实际位置未排序。仅对对象创建时间进行排序,但这似乎没有用。所以无法从左到右或从上到下扫描。

Flash 已死。

Macromedia Flash 8 (it's really obsolete, isn't it?)

在我看来,那是他们在上面加了 8 的那一天,那是什么时候,2006 年?

(完全个人观点,从来没有一根驳船杆足够长让我靠近闪光灯,我为曾经不得不挣扎的一切感到遗憾闪光的可憎)

更好的命中测试。

边界圆测试

对于速度,您可以进行缩短距离测试(边界圆测试)。基本上测试两个圆圈是否重叠。

  • 如果子弹 B 的半径约为 4 像素,而坏人 D 的半径约为 100 像素,则 if (D.x - B.x) * (D.x - B.x) + (D.y - B.y) * (D.y - B.y) < 4 * 4 + 100 * 100 then Hit。假设 B.x B.yD.xD.y是对象的中心坐标

边界椭圆测试

如果坏家伙不是正方形,以至于它们的宽度与高度明显不同,您可以修改上述测试以进行边界椭圆测试。您将需要获取宽高比并缩放高度计算。

所以如果坏家伙有宽度和高度D.w = 100 D.h = 50

  • 然后if (D.x - B.x) * (D.x - B.x) + (D.y - B.y) * (D.y - B.y) * (D.w / D.h) < 4 * 4 + D.w * D.w then Hit。假设B.xB.yD.xD.y是对象的中心坐标。并假设子弹与坏家伙相比相对较小。

边界框测试。 A.K.A。 AABB(轴对齐边界框)

您还可以进行边界框测试,测试包含子弹和坏家伙的框是否重叠。如果您不必计算左右顶部和底部边缘,这大约是最快的。

  • if not (B.leftEdge > D.rightEdge or B.rightEdge < D.leftEdge or B.topEdge > D.bottomEdge or B.bottomEdge < D.topEdge) then Hit

如果在设置时将子弹大小添加到敌人边界框的边界框,可以更快一些。

  • if not (B.x > D.rightEdge or B.x < D.leftEdge or B.y > D.bottomEdge or B.y < D.topEdge) then Hit(注意边缘减去半个项目符号宽度和高度,从左到右,从上到下添加。

更快的速度

如果你知道有一个区域子弹和坏家伙不相互作用,你可以进一步改进测试。 EG 从左到右的侧滚动条坏家伙永远不会接近屏幕宽度的 1/3,然后只有超过屏幕宽度的 1/3 时才测试项目符号。或者跟踪最左边的坏家伙,只测试距离左边大于该距离的子弹。如果子弹预计不会击中任何东西,除非它们已经飞行超过 n 帧,您也可以这样做。

测试是否命中测试

所有测试都是近似命中。如果您仍然想要精确命中测试,请使用上述方法之一来确定是否执行您正在使用的更详细和更慢的测试。

  • If boundingBox == true then do hitTest

这样你只有在很有可能命中时才使用慢速测试。