多数の独立した俳優をリアルタイムで管理する


8

私は大規模なリアルタイムストラテジーゲーム(理想的には数千のユニットを同時にアクティブにする)に取り組んでいますが、驚くほど遅くなることなくすべてのユニットを一度に管理するのに問題があります。問題は、タイムステップごとにすべての位置と状態を更新するのに時間がかかることです。これを軽減するための設計パターン/方法論/ヒントを知っていますか?


1
あなたの質問はかなり異なるように見えるかもしれませんが、ここで説明されているように同じアルゴリズムを使用できます。そのアルゴリズムで並列処理を使用する必要はなく、1つだけでパフォーマンスが向上します。
Ali1S232 2011

たとえば、2つのコアがあり、それらの半分の更新に時間がかかりすぎる場合、更新の並列化は役に立ちませんが、複数のコアが利用可能で、まだそれらを使用していない場合は、役立つはずです。理想的には、1つのタイムステップごとにすべてのユニットを更新する必要のないソリューション、または更新を単純化してできるようにする方法が必要です。このタイムステップの大きさは?それはドローフレームから独立していますよね?
Blecki

4
あなたが最初にできることは、あなたの速度は独立した俳優のとは何の関係もないことを認識することです。それはそれらの俳優がしていることと関係があります。私が10万人の独立したアクターが60fpsを超える更新を行っているif not dead position += 1場合、または1つのアクターが無限ループになる場合は1fps未満の更新を行うことができます。アルゴリズムの一部-これらのユニットが実行していることの一部-は、アルゴリズムの実行方法と比べて高すぎるため、それだけです。考えられる原因はさまざまであり、それぞれに考えられる戦略もさまざまです。
doppelgreener 2011

回答:


4

このような大規模なエンティティシステムのパフォーマンスを測定および最適化する場合、2つの異なる点を考慮する必要があります。

低レベルでは、すべてのアクティブなエンティティの反復と更新のコストを削減するために、SoA(配列の構造体)などの効率的なストレージレイアウトを使用するように煮詰める傾向があるエンティティの物理表現があります。

より高いレベルでは、意思決定ロジック、一般的なゲームロジック、AI、パスファインディングがあります。これらはすべて、レンダリングと同じ更新レートで実行する必要がないという共通のタスクです。

Nフレームごとにこれらのタスクを実行するという単純なアプローチをとると、フレーム時間が不均一になるため、いくつかのフレームにわたってコストを償却することは有益な傾向があります。

タスクが本質的に増分である場合、アルゴリズムの一部をフレームごとに実行し、部分的な結果を更新で使用できます。

タスクが主にモノリシックであるがエンティティごとに分離可能である場合、フレームごとにゲームエンティティのサブセットに対してそのタスクを実行し、ラウンドロビン方式でそれらの間でローテーションできます。これには、全員が一度に行動する必要がないため、パスファインディングやAIなどの複雑さを軽減するという利点があります。

私が取り組んだ大規模な戦術RTSでは、ゲームエンティティの近傍を見つけるために、高レベルのアルゴリズムで低レベルの表現をクエリするための堅牢なデータ構造に焦点を当てました。低レベルの更新プロセスは、ゆっくりと更新される高レベルのシミュレーションによって提供されるインテントに作用し、最終的には安価なパーティクルシミュレーションに煮詰められ、数千にスケールアップしました。


+1。私の考えは正確です。特に、ロジックを数サイクルごとにのみ処理される管理対象グループに減らし、そのようなグループはすべて処理のために交互に配置される可能性があります。
エンジニア

1

私が覚えている限り、ゲームは常に10,000ユニット未満です。エンパイアアースはハックによって14000まで到達する可能性がありますが、誰もその時点まで到達することはできませんが、私がその数を超えて覚えているゲームはありません。したがって、10,000個のオブジェクトの静的配列を用意するだけでは、必要以上のことのようです。

10000を超えるオブジェクトを反復処理することは大したことではないことを知っているので、アルゴリズムの実行がO(n)よりも遅い場合、多くの時間を消費する可能性があります。たとえば、2つのオブジェクトごとに衝突検出を確認しようとすると、O(n ^ 2)時間かかります。だから、どういうわけかあなたのアルゴリズムを破る必要があります。今考えることができるすべてのもののサンプルアルゴリズムを確認しましょう。

  1. 衝突検出:すべての衝突検出アルゴリズムについて、2つのオブジェクトごとにチェックする必要がありますが、ループの開始のチェックをいくつか省くことができます。私がコメントで提案したように、あなたはこの質問のために与えられた同じアルゴリズムを使うことができます。1つのスレッドと4つの領域を使用する場合でも、チェックをn *(n-1)から4 *(n / 4)((n-1)/ 4)に削減するため、複数のスレッドなどを使用する必要はありません。リージョンの数を最適化することで、さらに良い結果を得ることができます。私はあなたがO(n log(n))に到達することさえできる最高の数のリージョンを使うことで思う

  2. 移動するオブジェクトごとにパスを生成する必要があります。これまでに見た通常のシステムは非常に単純なものです。プレーヤーがユニットにどこかに移動するように命令するたびに、コンピューターがパスを計算します。その後、すべてのサイクルで、オブジェクトが移動できる場合は移動できず、移動できない場合はそのサイクルをスキップします。特別なことは何もありません。ただし、ここに示したアルゴリズムを変更して、パス検索の呼び出しを減らし、ユニットのグループごとにリアルタイムのパスファインディングを設定することもできますが、それは実際には必要ありません。

  3. 弾丸や爆弾などがユニットの1つに当たるかどうかを確認する必要があります。ここで衝突検出用に作成したのと同じ領域を使用できます。

  4. ユニットを選択するために、同じリージョンを使用することもできます。

一般に、最大で10,000または20,000の静的配列(または予約済みサイズの動的配列)を使用することをお勧めします。次に、それぞれがすべてのユニットを反復する約10または15のループを使用します。これは、すべてのプレイヤーのすべてのユニットを含む実際の大きな配列です。そのため、各インデックスには、ユニットの所有者とユニットのタイプに関する両方のデータがあります。また、プレーヤーごとに他の配列もいくつか作成します。これらのセカンダリ配列の各インデックスでは、オブジェクトへのポインタをメイン配列に格納するだけで済みます。

他に質問がある場合は、コメントに書き込んで私の回答に追加してください。


Empires Dawn of the Modern World :)に4万人以上いることを覚えています。レンダラーが画面上で1000程度しか維持できなかったことを恥じます。
deceleratedcaviar

@daniel:大したことではありません、将軍はユニット数に制限がありませんでした。私は数学の計算の基礎となる適切な数の単位を与えていました。40000と10000は、それほど大きな違いはありません。
Ali1S232 2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.