web-dev-qa-db-ja.com

エンティティコンポーネントシステムアーキテクチャオブジェクトは、定義によって指向されていますか?

エンティティコンポーネントシステムアーキテクチャ オブジェクト指向ですか?それは私にとってより手続き的または機能的なようです。私の意見では、OO言語で実装することを妨げるものではありませんが、OO 。

ECSはデータ(E&C)と動作(S)を分離しているようです。 証拠として

アイデアは、エンティティに埋め込まれたゲームメソッドを持たないことです。

および

コンポーネントは、特定の目的に必要な最小限のデータセットで構成されています

システムは、特定のコンポーネントを持つ一連のエンティティを使用する単一目的の機能です


オブジェクト指向であることの大部分はデータと動作を組み合わせることにあるため、これはオブジェクト指向ではないと思います。 証拠として

これとは対照的に、オブジェクト指向のアプローチでは、プログラマは、プログラムの他の部分から直接アクセスできない場所にデータを配置することが推奨されます。代わりに、データは、一般的にメソッドと呼ばれる特別に作成された関数を呼び出すことによってアクセスされます。

一方、ECSは、データを動作から分離することにすべて関わっているようです。

20
Daniel Kaplan

前書き


エンティティコンポーネントシステムは、オブジェクト指向のアーキテクチャ手法です。

オブジェクト指向プログラミングと同じように、この用語の意味について普遍的なコンセンサスはありません。ただし、エンティティコンポーネントシステムがinheritanceのアーキテクチャの代替として具体的に意図されていることは明らかです。継承階層は、オブジェクトisを表現するのに自然ですが、特定の種類のソフトウェア(ゲームなど)では、オブジェクトdoesを表現する方が適切です。

これは、C++やJavaでの作業に慣れている可能性が高い「クラスと継承」とは異なるオブジェクトモデルです。エンティティは、JavaScriptやSelfのプロトタイプのように、クラスと同じくらい表現力があり、これらのシステムはすべて、相互に実装できます。


Playerが、PositionVelocityKeyboardControlledの各コンポーネントを備えたエンティティであり、これらは明らかなことを行っているとしましょう。

entity Player:
  Position
  Velocity
  KeyboardControlled

PositionVelocityの影響を受け、VelocityKeyboardControlledの影響を受けるはずです。問題は、これらの影響をどのようにモデル化するかです。

エンティティ、コンポーネント、システム


コンポーネントに相互参照がないと仮定します。外部のPhysicsシステムがすべてのVelocityコンポーネントを走査し、対応するエンティティのPositionを更新します。 Inputシステムは、すべてのKeyboardControlledコンポーネントを走査して、Velocityを更新します。

          Player
         +--------------------+
         | Position           | \
         |                    |  Physics
       / | Velocity           | /
  Input  |                    |
       \ | KeyboardControlled |
         +--------------------+

これは基準を満たしています:

  • エンティティはゲーム/ビジネスロジックを表現しません。

  • コンポーネントは、動作を説明するデータを格納します。

システムは現在、イベントの処理とenactingコンポーネントによって記述された動作を担当しています。また、衝突などのエンティティ間の相互作用の処理も行います。

エンティティとコンポーネント


ただし、コンポーネントdoが相互に参照しているとします。これで、エンティティーは、いくつかのコンポーネントを作成し、それらを一緒にバインドし、それらの存続時間を管理するコンストラクターになりました。

class Player:
  construct():
    this.p = Position()
    this.v = Velocity(this.p)
    this.c = KeyboardControlled(this.v)

エンティティは、入力および更新イベントを直接コンポーネントにディスパッチする場合があります。 Velocityは更新に応答し、KeyboardControlledは入力に応答します。これはまだ私たちの基準を満たしています:

  • エンティティは、イベントをコンポーネントに転送するだけの「ダム」コンテナです。

  • 各コンポーネントは自身の動作を実行します。

ここで、コンポーネントの相互作用は明示的であり、システムによって外部から課されることはありません。動作を説明するデータ(速度の量は?)とそれを実行するコード(速度とは?)は、自然な形で結合されています。データは、動作のパラメーターとして表示できます。また、一部のコンポーネントはまったく機能しません。Position場所にいるの動作です。

相互作用は、エンティティのレベル(「PlayerEnemy…と衝突するとき」)または個々のコンポーネントのレベル(「Lifeを持つエンティティがStrength…を持つエンティティと衝突するとき」)で処理できます。

部品


エンティティが存在する理由は何ですか?単にコンストラクタの場合は、コンポーネントのsetを返す関数に置き換えることができます。後でエンティティをタイプでクエリする場合は、Tagコンポーネントを使用して、それを実行することもできます。

function Player():
  t = Tag("Player")
  p = Position()
  v = Velocity(p)
  c = KeyboardControlled(v)
  return {t, p, v, c}
  • エンティティは、可能な限りばかばかしく、単なるコンポーネントのセットです。

  • コンポーネントは以前と同様にイベントに直接応答します。

相互作用mustは抽象クエリで処理されるようになり、イベントをエンティティタイプから完全に分離します。 これ以上ありませんクエリするエンティティタイプ—任意のTagデータは、ゲームロジックよりもおそらくデバッグに使用する方が適切です。

結論


エンティティは、関数、ルール、アクター、またはデータフローの組み合わせではありません。それらは名詞であり、具体的な現象をモデル化しています。つまり、オブジェクトです。それはWikipediaが言うように、エンティティ–コンポーネントシステムは、一般的なオブジェクトをモデリングするためのソフトウェアアーキテクチャパターンです。

22
Jon Purdy

NO。そして、他に投票した人の数に驚いています!

パラダイム

Data-Oriented別名Data-Drivenarchitectureについて話しており、言語ではないためそれは書かれています。アーキテクチャは、プログラミングスタイルまたは paradigms の具現化です。これは通常、特定の言語で望ましくない方法で回避できます。


機能的ですか?

FunctionalProcedural プログラミングとの比較は、関連性があり意味のある比較です。ただし、「Functional」languageは「Procedural」paradigmとは異なることに注意してください。そして、あなたは/-できますHaskell のような関数型言語でECSを実装します。


凝集が起こる場所

あなたの観察は関連性があり、スポットオン

「... [ECS]は、OO言語での実装を妨げるものではありませんが、頑固に実装することは慣用的ではありませんOO =方法」


ECS/ESはEC/CEではありません

コンポーネントベースのアーキテクチャである「Entity-Component」と「Entity-Component-System」には違いがあります。これは進化するデザインパターンであるため、これらの定義は同じ意味で使用されています。 「EC」または「CE」または「エンティティコンポーネント」アーキテクチャコンポーネントに動作を配置「ES」または「ECS」アーキテクチャシステムに動作を配置。以下に、ECSの記事をいくつか示します。どちらも誤解を招くような命名法を使用していますが、全体的な概要を把握しています。

2015年にこれらの用語を理解しようとしている場合は、「エンティティコンポーネントシステム」への言及が「エンティティコンポーネントアーキテクチャ」を意味していないことを確認してください。

18
pup

エンティティコンポーネントシステム(ECS)は、システムの定義方法に応じて、OOPまたは機能的にプログラムできます。

OOPの方法:

私は、エンティティがさまざまなコンポーネントで構成されるオブジェクトであるゲームに取り組んできました。エンティティにはupdate関数があり、すべてのコンポーネントでupdateを順番に呼び出すことにより、オブジェクトを適切に変更します。これは明らかにOOPスタイルで-動作はデータにリンクされており、データは変更可能です。エンティティは、コンストラクタ/デストラクタ/更新を持つオブジェクトです。

より機能的な方法:

代替手段は、エンティティがメソッドなしのデータであることです。このエンティティは、それ自体で存在する場合もあれば、単にさまざまなコンポーネントにリンクされているIDである場合もあります。このようにして、完全に機能し、不変のエンティティと新しいコンポーネントの状態を生成する純粋なシステムを持つことが可能になります(一般的には行われません)。

(個人的な経験から)後者の方がより多くの牽引力を得ており、それには正当な理由があるようです。エンティティデータを動作から分離すると、より柔軟で再利用可能なコード(imo)になります。特に、バッチでコンポーネント/エンティティを更新するシステムを使用すると、パフォーマンスが向上し、多くのOOP ECSを悩ますエンティティ間メッセージングの複雑さを完全に回避できます。

TLDR:どちらの方法でも可能ですが、優れたエンティティコンポーネントシステムの利点は、そのより機能的な性質に由来すると私は主張します。

10
AGD

私はECSをOOPとは根本的に異なるものと考えており、データを機能性から非常に明確に分離し、本質的に機能的または特に手続き的により近いものと同じように見ている傾向があります。中央データベースを扱う一種のプログラミングにもいくつかの類似点があります。もちろん、私は正式な定義に関しては最悪の人です。私は、物事がどのようになりがちであるかだけに関心があります。

コンポーネントがデータフィールドを集約してパブリック/グローバルにアクセス可能にし、エンティティがコンポーネントを集約し、システムがそのデータの機能/動作を提供する、一種のECSを想定しています。これにより、通常オブジェクト指向のコードベースと呼ばれるものから、根本的に困難なアーキテクチャ特性がもたらされます。

そしてもちろん、人々がECSを設計/実装する方法には境界がぼやけており、そもそもECSを正確に構成するものについては議論があります。しかし、そのような境界は、関数型または手続き型言語と呼ばれるもので記述されたコードでもぼやけています。このすべてのあいまいさの中で、機能からデータを分離するECSの基本的な定数は、OOPよりも機能プログラミングまたは手続き型プログラミングにはるかに近いようです。

ECSがOOPのクラスに属していると考えるのが役に立たないと思う主な理由の1つは、OOPに関連付けられているSEプラクティスのほとんどが、パブリックインターフェースモデリングを使用して、パブリックインターフェースの安定性に関係していることです。 関数、データではありません。基本的な考え方は、パブリック依存関係の大部分は、具体的なデータではなく、抽象的な関数に向かって流れるということです。そのため、OOPを使用すると、基本的な設計動作の変更に非常にコストがかかる一方、具体的な詳細(機能の実装に必要なデータやコードなど)の変更は非常に安くなります。

ECSはこの点で根本的に異なります。パブリック依存関係の大部分が具体的なデータに向かって流れているときに、システムからコンポーネントへと、どのように物事が結合されるかを考えます。結果として、ECSに関連するすべてのSEプラクティスはデータの安定性を中心に展開します。これは、最も広く使用され、広く使用されているインターフェイス(コンポーネント)が実際には単なるデータだからです。

その結果、DXとGLエンジンは同じ安定したデータにアクセスできます。一方、それは非常に高価であり、たとえばMotionComponentのデータ表現を変更するには、一連のシステムを書き換える必要があります。

これは、少なくともカップリングの特性、および「パブリックインターフェイス」と「プライベート実装の詳細」を構成する要素の点で、従来OOPに関連付けられていたものとは正反対です。もちろん、どちらの場合も「実装の詳細」は簡単に変更できますが、ECSでは変更にコストがかかるのはデータの設計であり(データはECSの実装の詳細ではありません)、OOPでは機能の設計ですこれは変更にコストがかかります(関数の設計はOOPの実装の詳細ではありません)。つまり、「実装の詳細」の考え方はまったく異なります。メンテナンスの観点から見たECSの主な魅力の1つは、私のドメインでは、物事を行うために必要なデータが安定していて、正しく設計されていることです。そのデータを使用して実行できるさまざまなすべてのことよりも前に(クライアントが考えを変え、新しいユーザーの提案が殺到すると、それは常に変化します)。その結果、抽象的な機能から離れて生の中央データに依存関係を向け始めたとき、メンテナンスコストが急落していることに気付きました(ただし、すべてのデータが概念的に存在するにもかかわらず、どのシステムがどのコンポーネントにアクセスして不変条件を適切な程度に維持できるかについては注意が必要です)グローバルにアクセス可能)。

そして少なくとも私の場合、APIとすべてのコンポーネントを備えたECS SDKは実際にはCで実装されており、OOPとの類似点はありません。 ECSアーキテクチャにOOの固有のlackがあり、最も幅広い言語で使用できるプラグインアーキテクチャが必要であることを考えると、Cはこのような目的には十分すぎると感じました。とコンパイラ。 C++では物事が非常に便利になり、システムは複雑さの大部分をモデル化するため、システムは引き続きC++で実装されており、OOPに近いと見なされる可能性のある多くのものに使用されますが、それは実装の詳細のためです。建築設計自体は、まだ非常に手続き型のCに似ています。

したがって、少なくとも、定義上、ECSはOOであると言うことを試みるのはやや混乱します。少なくとも基本は、カプセル化から始まり、おそらく望ましい結合特性と見なされるもので終わる可能性がある、OOPに一般的に関連する多くの基本原則から完全に180度回転したものです。

3
user204677

データ指向エンティティコンポーネントシステムは、オブジェクト指向パラダイムと共存できます。-コンポーネントシステムは、ポリモーフィズムに適しています。 -コンポーネントは、POD(プレーンな古いデータ)とALSOオブジェクト(クラスとメソッドを含む)の両方にすることができ、コンポーネントクラスメソッドがローカルオブジェクトが所有するデータのみを操作する場合は、全体が「データ指向」のままです。

このパスを選択する場合は、仮想メソッドを使用しないことをお勧めします。仮想メソッドがある場合、コンポーネントは純粋なコンポーネントデータではなくなり、これらのメソッドの呼び出しコストが増えるため、これはCOMではありません。原則として、コンポーネントクラスには、外部への参照がないようにしてください。

例としては、vec2またはvec3、そのデータを操作するためのいくつかのメソッドを持つデータコンテナーなどがあります。

2
Homer