我在Java中实现了一个类似于 this one 的游戏,目前我发现我的粒子上限达到了约80k。我的游戏板是一个二维数组,引用了粒子'对象,每个对象必须每帧更新。不同种类的粒子'具有不同的行为,可以根据风或相邻粒子等环境条件移动或改变其状态。
一些可能的规则'可能有效:
我已经四处搜索过,并且无法找到任何看起来特别适合加速任务的算法或数据结构。似乎某种记忆可能有用吗?四叉树在这里有用吗?我已经看到它们在类似Conway的生命游戏中使用了Hashlife算法。或者,我是不是可以做太多来提高速度?
答案 0 :(得分:1)
Hashlife原则上会起作用,但有两个原因可能导致你没有像Conway Life那样得到更多的东西。
首先,它依赖于重复出现的模式。你拥有的单元格状态越多,平面结构越少,你遇到的缓存命中次数就越少,你就会越用蛮力。
其次,另一张海报指出涉及非本地效果的规则将意味着你的原语(在康威生活4x4中)将需要更大,所以你将放弃分裂并征服8x8或16x16或任何大小保证你可以在n / 2时间内正确计算中间部分。 由于各州的多样性,情况变得更糟。在Conway Life中,通常预先计算所有4x4网格,至少在缓存中有几乎所有相关的网格。 有2个州只有65536个4x4网格(现代平台上的花生)但只有3个有43046721。 如果你必须拥有8x8原语,它会非常迅速地超出任何实际存储空间。
因此原语越大,你拥有的状态就越多,这就变得很不现实。
解决原始大小的一种方法是让摇滚规则传播压力。因此,如果Rock + m(其中m> = n),Rock + n(n代表压力)在下一代中变为Rock +(n + 1)。高达某个阈值k,它转向沉积岩。
这意味着细胞仍然只依赖于它们的近邻,但又会使状态数倍增。
如果您在给出的示例中有像'Bird'这样的细胞类型,并且您的速度没有保持最小(在任一方向上都是-1,0,1),那么您将完全崩溃记忆。即使这样,这些规则的混乱性质也可能使这些区域的缓存命中率变得非常小。
如果您的规则没有导致稳定状态(或重复周期),例如Conway Life经常会记录回复的回报将受到限制,除非您的飞机大部分是空的。
答案 1 :(得分:0)
我不明白你的问题,但我认为cuda或OpenGL(一般来说是 GPU编程)可以轻松处理你的参考链接:https://dan-ball.jp/en/javagame/dust/
答案 2 :(得分:0)
我使用固定的NxN网格主要是因为每个帧周围有太多的点移动以受益于四叉树的递归细分特性。在这种情况下,具有适当调整的数据表示和存储器布局的简单数据结构可以在世界上产生重大影响。
我在这里为Java做的主要事实是避免将每个粒子建模为一个对象。它应该是原始数据,就像一些普通的旧数据,如浮点数或整数。您希望能够使用顺序处理来处理空间局部性的连续性保证,而不需要支付填充成本和每个类实例的8字节开销。将冷场远离热田。
例如,您不一定需要知道粒子的颜色来移动它并应用物理。因此,您不希望此处的AoS表示必须在序列物理传递过程中将粒子的颜色加载到缓存行中才能逐出它而不使用它。将尽可能多的相关内存一起用于缓存行,然后将其与特定传递的无关内存分开。
网格中的每个单元格应该只是将一个索引存储到一个粒子中,每个粒子都存储一个索引到单元格中的下一个粒子(一个单链表,但是一个需要不分配节点而只使用索引的侵入式列表进入数组)。 -1
可用于指示列表的结尾以及空单元格。
要查找感兴趣的粒子之间的碰撞,请查看与您正在测试的粒子相同的单元格,并且您可以并行执行此操作,其中每个线程处理一个或多个值为粒子的单元格。
考虑到每帧可以拥有的大量移动粒子,NxN网格应该非常精细。使用您创建的单元格数来查找适合您输入大小的最佳单元格。你甚至可能有多个网格。如果某些粒子不相互作用,请不要将它们放在同一网格中。这里不要担心网格的内存使用情况。如果每个网格单元只将32位索引存储到单元格中的第一个粒子,则200x200网格仅需要160千字节,每个粒子的索引开销为32位next
。
几年前,我使用上述技术制作了与此类似的东西(但没有与演示游戏一样多的有趣的粒子交互),它可以处理大约10密耳的粒子,然后开始低于30 FPS和更老只有2个核心的硬件。它确实使用了C以及SIMD和多线程,但我认为如果你这样做的话,你可以在Java中同时处理一大堆粒子来获得非常快速的解决方案。
当粒子从一个单元格移动到下一个单元格时,您所做的就是操纵几个整数将它们从一个单元格移动到另一个单元格。单元格不“拥有内存”或分配任何内存。它们只是32位索引。
要确定粒子占用哪个单元格,只需执行以下操作:
cell_x = (int)(particle_x[particle_index] / cell_size)
cell_y = (int)(particle_y[particle_index] / cell_size)
cell_index = cell_y * num_cols + cell_x
......比穿越树状结构更便宜的恒定时间操作,并且随着粒子移动而不得不重新平衡它。