绘制数千个粒子的更高效方法(Java/Android)

6
所以我正在编写一种类似于粒子模拟器的东西,如果你知道“掉落沙游戏”的话,就像那个。但现在我遇到了一个障碍。我的做法是创建一个粒子对象,目前基本上只有一个位置(int x,int y)。我用线程和Android面板的onDraw事件来绘制/移动它们。每次调用onDraw时,我循环遍历所有粒子,将它们向下移动一个像素,除非它们撞到底部,然后绘制它们。这相当流畅,直到我达到大约200个粒子,然后fps显着下降。我知道我的做法计算量很大,这是毫无争议的,但是否有任何方法可以允许绘制更多的粒子并减少延迟?

提前致谢。

5个回答

2

我猜您正在使用单像素绘图函数?这确实会很慢。

我看到了一些改进的方法。首先,将像素放入内存位图中,然后同时绘制整个位图。其次,由于粒子始终只向下移动一个像素,因此可以滚动部分位图而不是重新绘制所有内容。如果Android没有滚动功能,则只需将位图向下绘制一个像素,并为滚动上方的粒子启动一个新位图。您需要修复底部的粒子,但这些粒子较少。


这是Android的drawPoint(x,y,Paint)函数。 - Hamel

2
您可能想要了解OpenGL ES硬件加速和renderscript。这不会在代码方面给您提供更有效的解决方案(请参阅其他答案)。然而,它确实为您打开了更多的处理能力。您甚至可以在GPU上运行整个模拟(可能性,不知道您的实现细节)。 编辑
此外,如果您仍然决定在Java中进行处理,您应该查看DDMS中的方法分析。这将帮助您可视化性能瓶颈的位置。

+1:实际上,这是唯一合理的答案。OpenGL 的设计正是为了处理这种类型的任务。 - Rekin

2

我以前从未做过这样的事情,但我做过一些复杂的细胞自动机。如果这太模糊了,请谅解。

基本思想是对所有应该“保持下落”或“不移动”的粒子进行标记,并将它们从复杂处理中排除(使用专门的“下落”列表的短/快处理器 - 您只需要将每个像素下降一个像素即可)。

  • 静态粒子的加速度 - 静态粒子(我将其称为S粒子)不会移动。对于所有非移动区域进行标记(例如用户可能制作的免受重力影响的“墙壁”或“碗”)。如果稳定,则在其上方标记为S,例如对于液体,如果它在下方和两侧都有S粒子,则不会移动。对于形成堆的沙子,如果在其下面的三个位置中均有S,则会形成堆,您将得到漂亮的45度堆,我相信您可以更改它以使某些东西形成更陡峭或不那么陡峭的堆。进行从下到上的S映射。
  • 没有颗粒物质在其下面的颗粒物质的加速度是下落 - F颗粒物质。在它们下面有F颗粒的颗粒也是F颗粒。同样进行从下到上的标记。
  • 未标记为F或S的颗粒物质是复杂的,它们可能开始下落,停止下落或滚动,使用您已经拥有的慢处理器来处理它们,不应该有太多。

最终,您将拥有许多快速的粒子。那些在堆/湖中并那些正在下雨。剩余的颗粒物质位于斜坡边缘,湖泊顶部或其他复杂位置。与快速颗粒相比,它们不应该那么多。

每种颗粒物质都用某种颜色进行视觉标记,复杂颗粒物质为明亮红色。查找仍然很慢的情况,并查看您应该制作哪些其他类型的快速处理器。例如,您可能会发现制作大量沙堆会在斜坡上创建许多红色区域,您可能需要投资于加速沿着沙堆斜坡的“滚动区域”。

希望这有意义。不要忘记在弄清楚某些事情后返回并进行编辑!


这非常有帮助,我可能会这样做。 - Hamel

0
如果您将图像稍微模糊一下,那么您可以每次只移动一半的粒子,或者只移动四分之一的粒子并打印它们...这将减少计算量,用户也看不到,感觉所有的粒子都在移动。
但无论您选择什么方法,我认为您应该设置一个强大的限制,因为不是所有的用户都拥有强大的安卓设备。
祝好, 斯蒂芬

0

我认为如果粒子彼此靠近,您可以创建代表3个或更多粒子的对象。

在屏幕上显示几个粒子时,可能会忽略一些颗粒集合。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接