エンティティ コンポーネント システム (今後は ECS) の最速バージョンを C++ で実装する方法を知りたいです。
まず、用語について:
- シーンは、エンティティ(および一部の実装ではシステム)のコンテナーです。
- コンポーネントは単純なデータ ストレージです (位置、衝突ボックス、レンダリングするイメージなど)。
- システムは、システムの要件に適合するコンポーネントでロジックを実行します (これは、物理、プレーヤー入力、単純なレンダリングなどである可能性があります)。
- エンティティには、最終的な動作を構成するいくつかのコンポーネントが含まれています
私たちが思いついたすべてのデザインを以下にリストしました.
1.「素朴な」方法
シーンには、順序付けされていないすべてのエンティティが含まれています。
システムが更新されると、すべてのシステムがすべてのエンティティをループし、各エンティティに必要なすべてのコンポーネントが含まれているかどうかを確認してから、それらのエンティティに対して更新を実行する必要があります。
明らかに、この方法は、多数のシステムおよび/または多数のエンティティがある場合、あまりパフォーマンスが高くありません。
2.「ビットマスク列挙型」とマッピングの使用
各コンポーネントには、ビットマスクの形式でタイプ識別子が含まれています (例: 1u << 5
/ binary [0...]100000
)。その後、各エンティティはすべてのコンポーネントのタイプ識別子を構成できるため (すべてのタイプ ID がエンティティ内で一意であると仮定)、次のようになります。
1u << 5 | 1u << 3 | 1u << 1
binary [0...]101010
シーンには、システムが適切なエンティティを簡単に検索できるある種のマップが含まれています。
MovementSystem::update() {
for (auto& kv : parent_scene_) { // kv is pair<TypeID_t, vector<Entity *>>
if (kv.first & (POSITION | VELOCITY))
update_entities(kv.second); // update the whole set of fitting entities
}
}
長所:
- 単純な方法よりも高速
短所:
- システムは、更新されるたびに適切なエンティティを検索する必要があります。
- ビットマスク (列挙型) はビット数 ( の場合は 32、 の
uint32_t
場合は少なくとも 64unsigned long long
) に制限されており、場合によっては、ビットマスクが許可するよりも多くのコンポーネントが必要になることがあります。
3. システムを使用しない
この方法については、Danvilが以下の回答で説明しています。
長所:
- ビットマスクのことを完全に取り除きます。
- 設計 2 よりも高速になる可能性があります。
短所:
- に依存し
dynamic_cast
てコンポーネントを検索しますが、設計 #2 はコンポーネントを直接検索してから安全に検索できますstatic_cast
。
4.予備セットの使用
この方法は、以下の回答でskypjackによって説明されています。彼は彼のアプローチを非常に詳細に説明したので、彼の答えを読むことをお勧めします.