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

Posted

技术标签:

【中文标题】减少 hitTest 调用以提高 Flash 游戏性能的最佳实践【英文标题】:Best practice to cut down hitTest calls to improve performance of a flash game 【发布时间】:2017-08-14 10:12:07 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

Flash 已死。

Macromedia Flash 8(它真的已经过时了,不是吗?)

在我看来,他们在上面加了一个 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.xB.yD.xD.y是中心坐标对象

边界椭圆测试

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

所以如果坏家伙有宽度和高度D.w = 100D.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是对象的中心坐标。并假设与坏人相比,子弹相对较小。

边界框测试。又名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

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

【讨论】:

以上是关于减少 hitTest 调用以提高 Flash 游戏性能的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

做 hittest 时,圆圈对迷宫的不可见部分做出反应

First Responder 和 hitTest 方法之间有啥关系?

AS3 自定义命中测试

如何使用 httpbackend 测试 Restangular http 调用以测试成功和错误情况?

hitTest:withEvent源码分析

我的计时器通过我的游戏单次游戏后提高速度为什么?