互いに引き寄せられるサイズと速度がさまざまなオブジェクトがたくさんあります。更新するたびに、すべてのオブジェクトを調べて、他のすべてのオブジェクトの重力による力を加算する必要があります。それはあまりうまくスケールせず、ゲームで見つけた2つの大きなボトルネックの1つであり、パフォーマンスを改善するために何をすべきかわかりません。
パフォーマンスを改善できるはずだと感じています。常に、システム内のオブジェクトの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);
}
(たとえば、衝突テストなど、多くのコードを削除したことに注意してください。衝突を検出するためにオブジェクトを2回繰り返し処理することはありません)。
そのため、リスト全体を常に繰り返すわけではありません-最初のオブジェクトに対してのみそれを行います。オブジェクトが別のオブジェクトに向かって感じる力を見つけるたびに、他のオブジェクトは同じ力を感じるので、両方を更新しますそれら-そして、その最初のオブジェクトは、更新の残りのために再び考慮される必要はありません。
Gravity.ForceUnderGravity(...)
そしてMotion.Velocity(...)
、などの機能がちょうどXNAのベクトル数学に建てられたのビットを使用しています。
2つのオブジェクトが衝突すると、質量のない破片が作成されます。それは別のリストに保持され、速度計算の一部として大規模なオブジェクトはデブリを反復しませんが、デブリの各断片は大規模な粒子を反復する必要があります。
これは、信じられないほどの限界まで拡大する必要はありません。世界は無制限ではなく、それを横切るオブジェクトを破壊する境界線を含んでいます-おそらく1000程度のオブジェクトを処理できるようにしたいのですが、現在、ゲームは200前後で窒息し始めています。
これをどのように改善できるかについての考えはありますか?ループの長さを数百から数個に削減するために使用できるヒューリスティックな方法はありますか?すべての更新よりも頻繁に実行できないコードがありますか?まともなサイズの世界を可能にするのに十分な速度になるまで、マルチスレッドするだけですか?速度計算をGPUにオフロードする必要がありますか?もしそうなら、私はそれをどのように設計しますか?GPUに静的な共有データを保持できますか?GPUでHLSL関数を作成し、それらを(XNAを使用して)任意に呼び出すことができますか、それとも描画プロセスの一部にする必要がありますか?
G * m1 * m2 / r^2
はGです。ここで、Gは動作を微調整するためのものです。(ユーザーがシステムを邪魔する可能性があるため、パスをたどることはできませんが)