我有一堆大小和速度各异的物体,它们相互吸引。每次更新时,我都必须遍历每个对象并合计由于每个其他对象的重力而产生的力。它的伸缩性不是很好,是我在游戏中发现的两个主要瓶颈之一,我不确定该如何提高性能。
这感觉就像我应该可以提高性能。在任何给定时间,系统中大约99%的对象对对象的影响都可以忽略不计。我当然不能按质量对物体进行排序,而只能考虑前10个最大的物体或某些物体,因为力随距离的变化比随质量的变化大(方程沿的线force = mass1 * mass2 / distance^2
)。我认为,最好的办法是考虑最大的物体和最接近的物体,而忽略世界另一端可能无法影响任何事物的数百个微小的岩石碎片,但要找出哪些物体是最近我有遍历所有的对象,他们的立场正在发生变化不断,所以这不是我只能做一次。
目前我正在做这样的事情:
private void UpdateBodies(List<GravitatingObject> bodies, GameTime gameTime)
{
for (int i = 0; i < bodies.Count; i++)
{
bodies[i].Update(i);
}
}
//...
public virtual void Update(int systemIndex)
{
for (int i = systemIndex + 1; i < system.MassiveBodies.Count; i++)
{
GravitatingObject body = system.MassiveBodies[i];
Vector2 force = Gravity.ForceUnderGravity(body, this);
ForceOfGravity += force;
body.ForceOfGravity += -force;
}
Vector2 acceleration = Motion.Acceleration(ForceOfGravity, Mass);
ForceOfGravity = Vector2.Zero;
Velocity += Motion.Velocity(acceleration, elapsedTime);
Position += Motion.Position(Velocity, elapsedTime);
}
(请注意,我删除了很多代码-例如碰撞测试,我没有第二次遍历对象以检测碰撞)。
因此,我并不总是遍历整个列表-我只对第一个对象执行此操作,并且每次对象找到它对另一个对象的感觉力时,另一个对象都感觉到相同的作用力,因此它只会更新两个对象它们-然后在其余的更新中不必再次考虑第一个对象。
在Gravity.ForceUnderGravity(...)
和Motion.Velocity(...)
等功能,只需用一点XNA的内置矢量数学。
当两个物体碰撞时,它们会产生无质量的碎片。它被保存在一个单独的列表中,并且作为速度计算的一部分,块状对象不会在碎片上进行迭代,但是每块碎片都必须在块状粒子上进行迭代。
这不必扩展到令人难以置信的极限。这个世界不是无限的,它包含一个边界,该边界可以摧毁穿过它的物体-我希望能够处理大约一千个物体,目前游戏开始cho绕200个左右。
关于如何改善这一点有什么想法吗?我可以使用一些启发式方法将循环长度从几百个减少到几个吗?我执行的某些代码少于每次更新的执行频率?我是否应该对其多线程化直到它足够快以允许一个体面的世界?我应该尝试将速度计算卸载到GPU吗?如果是这样,我将如何设计?我可以在GPU上保留静态共享数据吗?我可以在GPU上创建HLSL函数并任意调用它们(使用XNA),还是必须将它们作为绘制过程的一部分?
G * m1 * m2 / r^2
,其中G只是用来调整行为。(尽管我不能随便他们走,因为用户可能会打扰系统)