我正在开发一款游戏,游戏中有大量的敌人群,敌人和障碍物都需要渲染到一个遮罩表面上,我使用了一个自定义的绘制通道来渲染所有可见的敌人和障碍物,根据深度进行排序。 我使用了一个ds_priority来进行排序:向 priority 中添加每个实例的深度,然后使用 ds_priority_delete_max 在循环中弹出实例。 当屏幕上有约1000个敌人时,这个通道本身会花费5-9毫秒。因此,我设置了一个可复现的基准测试:游戏暂停(Draw继续运行),摄像机冻结,1295个敌人+550个障碍物=1845个对象。结果如下:

- 原始(ds_priority):9.57毫秒
- 同一循环但不实际执行绘制调用:9.48毫秒
- 去除其他嫌疑者(祖先检查,范围,while vs repeat):无差异
- 平面数组,未排序:1.18毫秒
- 数组+根据深度进行计数排序:1.40毫秒

因此,9.6毫秒中有8.2毫秒花费在了ds_priority_delete_max上。所有1820个绘制调用一起只花费了0.16毫秒。 在我的测量中,delete_max表现出像线性扫描整个队列一样的行为。将其调用一次每个元素,循环就变成了O(n²)。它在几百个实例时不会出现,但在扩大时会爆炸。解决方案:两个平行数组(ids + depths)和根据floor(depth)进行计数排序,然后从远到近循环。计数排序在一个桶内是稳定的,所以我可以丢弃我的破坏者。同一张图像,约8毫秒/帧的节省。如果您在循环中弹出ds_priority的几百个条目,可能值得测量。祝好!希望对某些人有所帮助。