問題タブ [entity-component-system]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
architecture - コンポーネントベースのゲームエンジン設計
私はゲーム エンジンの設計 (特に 2D ゲーム エンジンに焦点を当てていますが、3D ゲームにも適用可能) に注目しており、その方法に関する情報に興味があります。最近では、多くのエンジンが、従来の深いオブジェクト階層ではなく、コンポーネント ベースの設計に移行していると聞きました。
これらの種類の設計がどのように実装されることが多いかについての情報への良いリンクを知っていますか? 私はあなたの階層を進化させたのを見てきましたが、詳細な情報をもっと多く見つけることはできません (ほとんどは「階層ではなくコンポーネントを使用する」と言っているようですが、考え方を変えるには少し努力が必要であることがわかりました) 2 つのモデルの間)。
これに関する優れたリンクや情報、さらには本をいただければ幸いです。ただし、ここでのリンクと詳細な回答が優先されます。
c++11 - エンティティ コンポーネント システムの設計
エンティティ コンポーネント システム (今後は ECS) の最速バージョンを C++ で実装する方法を知りたいです。
まず、用語について:
- シーンは、エンティティ(および一部の実装ではシステム)のコンテナーです。
- コンポーネントは単純なデータ ストレージです (位置、衝突ボックス、レンダリングするイメージなど)。
- システムは、システムの要件に適合するコンポーネントでロジックを実行します (これは、物理、プレーヤー入力、単純なレンダリングなどである可能性があります)。
- エンティティには、最終的な動作を構成するいくつかのコンポーネントが含まれています
私たちが思いついたすべてのデザインを以下にリストしました.
1.「素朴な」方法
シーンには、順序付けされていないすべてのエンティティが含まれています。
システムが更新されると、すべてのシステムがすべてのエンティティをループし、各エンティティに必要なすべてのコンポーネントが含まれているかどうかを確認してから、それらのエンティティに対して更新を実行する必要があります。
明らかに、この方法は、多数のシステムおよび/または多数のエンティティがある場合、あまりパフォーマンスが高くありません。
2.「ビットマスク列挙型」とマッピングの使用
各コンポーネントには、ビットマスクの形式でタイプ識別子が含まれています (例: 1u << 5
/ binary [0...]100000
)。その後、各エンティティはすべてのコンポーネントのタイプ識別子を構成できるため (すべてのタイプ ID がエンティティ内で一意であると仮定)、次のようになります。
シーンには、システムが適切なエンティティを簡単に検索できるある種のマップが含まれています。
長所:
- 単純な方法よりも高速
短所:
- システムは、更新されるたびに適切なエンティティを検索する必要があります。
- ビットマスク (列挙型) はビット数 ( の場合は 32、 の
uint32_t
場合は少なくとも 64unsigned long long
) に制限されており、場合によっては、ビットマスクが許可するよりも多くのコンポーネントが必要になることがあります。
3. システムを使用しない
この方法については、Danvilが以下の回答で説明しています。
長所:
- ビットマスクのことを完全に取り除きます。
- 設計 2 よりも高速になる可能性があります。
短所:
- に依存し
dynamic_cast
てコンポーネントを検索しますが、設計 #2 はコンポーネントを直接検索してから安全に検索できますstatic_cast
。
4.予備セットの使用
この方法は、以下の回答でskypjackによって説明されています。彼は彼のアプローチを非常に詳細に説明したので、彼の答えを読むことをお勧めします.
c++ - c++ エンティティ コンポーネント システムとテンプレートを使用したコンポーネントへのアクセス
私は独自のエンティティ コンポーネント システムの作成に取り組んでおり、次のようにしてコンポーネントを取得できるように設定しています。
上記の関数は次のようになります。
次に、見つかった場合は関連付けられた id に基づいてコンポーネントを返し、そうでない場合はコンポーネントを返しますnullptr
。
- 私がしていることは実行可能ですか?
- Component から派生した型のみをパラメーターとして使用できるようにする方法はあります
GetComponent
か?
c++ - エンティティ コンポーネント システム内のシステムにエンティティを効率的に一致させる方法
私は、コンパイル時にコンポーネント タイプとシステム シグネチャが認識される、データ指向のエンティティ コンポーネント システムに取り組んでいます。
エンティティはコンポーネントの集合体です。コンポーネントは、実行時にエンティティから追加/削除できます。
コンポーネントは、ロジックのない小さなクラスです。
シグネチャは、コンパイル時のコンポーネント タイプのリストです。署名に必要なすべてのコンポーネント タイプがエンティティに含まれている場合、そのエンティティは署名に一致すると見なされます。
短いコード サンプルは、ユーザー構文がどのように見えるか、および意図された使用法が何であるかを示します。
現在、操作を使用してエンティティが署名と一致するかどうかを確認していstd::bitset
ます。ただし、署名の数とエンティティの数が増えるとすぐにパフォーマンスが低下します。
擬似コード:
これは機能しますが、ユーザーがforEntitiesMatching
同じ署名で複数回呼び出すと、すべてのエンティティを再度照合する必要があります。
キャッシュに適したコンテナーにエンティティを事前にキャッシュするためのより良い方法もあるかもしれません。
コンパイル時のマップ( として実装)を作成するある種のキャッシュを使用してみましたstd::tuple<std::vector<EntityIndex>, std::vector<EntityIndex>, ...>
。ここで、キーはシグネチャ タイプ (すべてのシグネチャ タイプには のおかげで一意のインクリメンタル インデックスがありSignatureList
ます) であり、値はエンティティ インデックスのベクトルです。
キャッシュタプルを次のようなもので埋めました:
そして、マネージャーの更新サイクルごとにクリアしました。
残念ながら、私のすべてのテストで、上記の「生の」ループよりも遅く実行されました。また、より大きな問題があります: への呼び出しがforEntitiesMatching
実際にコンポーネントをエンティティから削除または追加するとどうなるでしょうか? forEntitiesMatching
後続の呼び出しでは、キャッシュを無効にして再計算する必要があります。
エンティティを署名に一致させるより速い方法はありますか?
コンパイル時に多くのことがわかっています(コンポーネント タイプのリスト、シグネチャ タイプのリストなど) -コンパイル時に生成できる、「ビットセットのような」マッチングに役立つ補助データ構造はありますか? ?
oop - エンティティ コンポーネント システムの継承
エンティティ コンポーネント システムについて私がオンラインで読んだほとんどの資料は、それが継承の使用から遠ざかるために使用されていることを示しているようです。しかし、私が知りたいのは、ECS と一緒に継承を使い続けることは可能ですか?
エンジン内に、ほぼ同じ機能を持つ特定の数のエンティティがあるとします。たとえば、移動可能なエンティティ。MovableEntity
必要なコンポーネントを追加するオブジェクトを作成することは可能ですか?