コンポーネントエンティティシステム-更新と呼び出し順序


10

コンポーネントがすべてのフレームを更新できるようにする(そしてこの機能を必要のないコンポーネントから除外する)ために、UpdateComponentコンポーネントを作成するというアイデアを得ました。MovableComponent(速度を保持する)などの他のコンポーネントは、IUpdatable抽象クラスを継承します。これによりMovableComponentUpdate(gametime dt)メソッドへのポインタとへのポインタをRegisterWithUpdater()提供するメソッドの実装が強制されUpdateComponentますMovableComponent。多くのコンポーネントがこれを実行し、誰が何であるかを気にすることなくUpdateComponent、すべてのUpdate(gametime dt)メソッドを呼び出すことができます。

私の質問は:

  1. これは、正常または誰かが使用しているもののように見えますか?この件については何も見つかりません。
  2. 物理学などのコンポーネントの順序を変更してから位置を変更するにはどうすればよいですか?これも必要ですか?
  3. フレームごとに処理する必要があるコンポーネントが実際に処理されることを保証する他の方法は何ですか?

編集
私はエンティティマネージャに更新可能なタイプのリストを与える方法を検討していると思います。次に、そのタイプのすべてのコンポーネントを、エンティティごとに管理するのではなく更新できます(とにかく、私のシステムのインデックスにすぎません)。

まだ。私の質問は引き続き有効です。これが理にかなっているのか、通常のことなのか、他の人が何をする傾向があるのか​​はわかりません。

また、不眠症の人々は素晴らしいです! /編集

前の例のコードを煮詰めました:

class IUpdatable
{
public:
    virtual void Update(float dt) = 0;
protected:
    virtual void RegisterAsUpdatable() = 0;
};

class Component
{
    ...
};

class MovableComponent: public Component, public IUpdatable
{
public:
    ...
    virtual void Update(float dt);
private:
    ...
    virtual void RegisterWithUpdater();
};

class UpdateComponent: public Component
{
public:
    ...
    void UpdateAll();
    void RegisterUpdatable(Component* component);
    void RemoveUpdatable(Component* component);
private:
    ...
    std::set<Component*> updatables_;
};

更新できないコンポーネントの例はありますか?それはかなり役に立たないようです。更新関数を仮想関数としてコンポーネントに配置します。それからちょうどエンティティ内のすべてのコンポーネントを更新し、「UpdateComponent」は必要ありません
はMaik Semder

一部のコンポーネントは、データホルダーに似ています。PositionComponentと同様。多くのオブジェクトは位置を持つことができますが、それらが多数である可能性がある静止している場合、それらすべての追加の仮想呼び出しが蓄積する可能性があります。または、HealthComponentと言います。フレームごとに何もする必要はありません。必要なときに変更するだけです。オーバーヘッドはそれほど悪くないかもしれませんが、私のUpdateComponentは、すべてのコンポーネントにUpdate()を含めないようにする試みでした。
ptpaterson 2011

5
データのみを保持し、時間の経過とともにデータを変更する機能を持たないコンポーネントは、定義上、コンポーネントではありません。時間の経過とともに変化するコンポーネントの一部が機能的に存在する必要があるため、更新機能が必要です。コンポーネントに更新機能が必要ない場合は、コンポーネントではないことがわかっているので、設計を再考する必要があります。ヘルスコンポーネントの更新機能は理にかなっています。たとえば、NPCがしばらくの間のダメージから回復するようにしたい場合です。
Maik Semder、2011

@Maik私のポイントは、決して変更されない/変更できないコンポーネントであるということではありませんでした。私はそれがばかげていることに同意します。すべてのフレームを更新する必要はなく、必要に応じて情報を変更するよう通知されます。長期にわたる健康の例では、更新がある健康ボーナスコンポーネントがあります。2つを組み合わせる理由は特にないと思います。
ptpaterson 2011

また、私が投稿したコードには、UpdateComponentの概念を説明するために必要なものだけが含まれていることにも注意してください。コンポーネント間の他のすべての形式の通信は除外されます。
ptpaterson 2011

回答:


16

コンポーネントシステムの主な利点の1つは、キャッシュパターンを利用できることです。同じコードを何度も実行するために優れたicacheと予測が得られ、オブジェクトを同種のプールに割り当てることができ、vtableがどっちも暑い。

コンポーネントを構造化した方法では、この利点は完全になくなり、実際には、継承ベースのシステムと比較して、仮想呼び出しとvtablesを使用したオブジェクトが増えるため、パフォーマンスが低下する可能性があります。

あなたがしなければならないことは、タイプごとにプールを保存し、更新を実行するために各タイプを個別に繰り返すことです。

これは、正常または誰かが使用しているもののように見えますか?この件については何も見つかりません。

それは有利ではないため、大規模なゲームでは一般的ではありません。それは多くのゲームで一般的ですが、技術的に面白くないので、誰もそれについて書いていません。

物理学などのコンポーネントの順序を変更してから位置を変更するにはどうすればよいですか?これも必要ですか?

C ++などの言語のコードには、実行を順序付ける自然な方法があります。その順序でステートメントを入力します。

for (PhysicsComponent *c : physics_components)
    c->update(dt);
for (PositionComponent *c : position_components)
    c->update(dt);

実際には、そのような方法で堅牢な物理システムが構築されていないため、これは意味がありません。単一の物理オブジェクトを更新することはできません。代わりに、コードは次のようになります。

physics_step();
for (PositionComponent *c : position_components)
    c->update(dt);
// Updates the position data from the physics data.

ありがとう。私はこのプロジェクト全体を、データ指向(データ駆動とは異なる)を念頭に置いて開始し、キャッシュミスなどを防止しました。しかし、コーディングを始めたら、ドットコムで機能するものを作ることにしました。それは私に物事を難しくしたことがわかりました。そして真面目な人にとって、その不眠症の記事は素晴らしかったです!
ptpaterson 2011

@ジョー+1は非常に良い答えです。icacheとdcacheが何であるか知りたいのですが。ありがとう
レイデイ

命令キャッシュとデータキャッシュ。コンピュータアーキテクチャの紹介テキストは、それらをカバーする必要があります。

@ptpaterson:Insomniacプレゼンテーションに小さな間違いがあることに注意してください。コンポーネントクラスにはその名簿インデックスが含まれている必要があります。そうでない場合、名簿インデックスにプールインデックスの個別のマッピングが必要です。

3

あなたが話していることは合理的でかなり一般的だと思います。これにより、さらに情報が得られる場合があります。


数週間前にその記事を見つけたと思います。コンポーネントベースのエンティティシステムのいくつかの非常に単純なバージョンを一緒にコーディングすることができました。すべての記事と例をまとめて、私がやりたいことができるようにしようとしています。ありがとう!
ptpaterson 2011

0

私はこれらのアプローチが好きです:

まもなく:コンポーネント内で更新動作を維持しないでください。コンポーネント動作ではありません。動作(更新を含む)は、一部の単一インスタンスサブシステムに実装できます。このアプローチは、複数のコンポーネントの同様の動作をバッチ処理するのにも役立ちます(おそらく、コンポーネントデータにparallel_forまたはSIMD命令を使用します)。

IUpdatableのアイデアとUpdate(gametime dt)メソッドは、制限が少なすぎるようで、追加の依存関係を導入します。サブシステムアプローチを使用していない場合は問題ないかもしれませんが、サブシステムを使用する場合は、IUpdatableは階層の冗長レベルです。結局のところ、MovingSystemは、これらのコンポーネントを持つすべてのエンティティのLocationおよび/またはVelocityコンポーネントを直接更新する必要があることを認識しているため、中間のIUpdatableコンポーネントは必要ありません。

ただし、Updatableコンポーネントを使用して、LocationコンポーネントやVelocityコンポーネントがあるにもかかわらず、一部のエンティティの更新をスキップできます。Updatableコンポーネントには、設定可能なブールフラグを設定できます。これによりfalse、この特定のエンティティを現在更新してはならないことをすべてのUpdatable対応サブシステムに通知します(このようなコンテキストでは、Freezableがコンポーネントにより適切な名前のようです)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.