コンポーネントベースのゲームでエンティティの状態とアニメーションを更新するにはどうすればよいですか?


10

学習目的で(後で一部のゲームで使用するため)コンポーネントベースのエンティティシステムを設計しようとしていますが、エンティティの状態の更新に関して問題が発生しています。

コンポーネント間の依存関係を防ぐために、コンポーネント内にupdate()メソッドを含めたくありません。

私が現在考えているのは、コンポーネントがデータを保持し、システムがコンポーネントを更新することです。

したがって、Transform、Movement、State、Animation、Renderingの各コンポーネントを持ついくつかのエンティティ(たとえば、player、enemy1、enemy2)を含む単純な2Dゲームがある場合、次のようにする必要があります。

  • すべてのMovementコンポーネントを移動し、Stateコンポーネントを更新するMovementSystem
  • また、アニメーションコンポーネントを更新するRenderSystem(アニメーションコンポーネントは、状態ごとに1つのアニメーション(つまり、フレーム/テクスチャのセット)を持つ必要があり、それを更新することは、現在の状態に対応するアニメーション(jumping、moving_leftなど)を選択することを意味します。フレームインデックスの更新)。次に、RenderSystemは、Renderコンポーネントを各エンティティのアニメーションの現在のフレームに対応するテクスチャで更新し、すべてを画面にレンダリングします。

Artemisフレームワークのようないくつかの実装を見てきましたが、この状況を解決する方法がわかりません。

私のゲームに次のエンティティがあるとします。各エンティティには、一連の状態と、状態ごとに1つのアニメーションがあります。

  • プレーヤー:「アイドル」、「移動」、「ジャンプ」
  • enemy1:「moving_up」、「moving_down」
  • enemy2: "moving_left"、 "moving_right"

各エンティティの現在の状態を更新するために最も受け入れられているアプローチは何ですか?考えられる唯一のことは、エンティティのグループごとに個別のシステムを持ち、状態コンポーネントとアニメーションコンポーネントを個別に持つことです。そのため、PlayerState、PlayerAnimation、Enemy1State、Enemy1Animation ... PlayerMovementSystem、PlayerRenderingSystem ...がありますが、これは悪いことだと思いますソリューションとコンポーネントベースのシステムを持つ目的を壊します。

ご覧のように、私はここでかなり迷っていますので、どんな助けにも感謝します。

編集:私が意図したとおりにこの作業を行うための解決策はこれです:

すべてのエンティティに使用できるように、statecomponentとanimationcomponentを十分に汎用的にします。それらに含まれるデータは、再生されるアニメーションや使用可能な状態などを変更するための修飾子になります。–バイト56

今、私はこれらの2つのコンポーネントを再利用できるように十分に汎用的に設計する方法を理解しようとしています。各状態(ウォーキング、ランニングなど)のUIDを持ち、この識別子でキー設定されたAnimationComponentにマップ内のアニメーションを格納することは良いソリューションでしょうか?


私はあなたがこれを見たと思います:エンティティまたはコンポーネントの状態変化?あなたの質問はそれと根本的に異なりますか?
MichaelHouse

@ Byte56はい、数時間前に読みました。あなたがそこに提案した解決策は、私がここで公開したアイデアに似ています。しかし、私の問題は、StateComponentとAnimationComponentがシステム内のすべてのエンティティで同じでない場合に発生します。そのシステムを、可能な同じ状態とアニメーションを持つエンティティのグループを処理する小さなシステムに分割する必要がありますか?(より明確にするために私の元の投稿の最後の部分を参照してください)
ミヴィクリン

1
あなたは作るstatecomponentanimationcomponentすべてのエンティティのために使用される一般的な十分。それらに含まれるデータは、再生されるアニメーションや使用可能な状態などを変更するための修飾子になります。
MichaelHouse

依存関係について話すとき、データの依存関係または実行順序の依存関係を意味しますか?また、提案するソリューションでは、MovementSystemは何かが動くことができるさまざまな方法をすべて実装する必要がありますか?これは、コンポーネントベースのシステムのアイデアを壊しているように見えます...
ADB

@ADBデータの依存関係について話している。アニメーションを更新する(たとえば、move_rightアニメーションからmove_leftアニメーションに変更する)には、エンティティの現在の状態を知る必要があり、これらの2つのコンポーネントをより汎用的にする方法がわかりません。
miviclin

回答:


5

私見は、Movement成分(現在の状態を保持しなければならないMovement.state)とAnimation成分がの変化を観察すべきであるMovement.state(その現在のアニメーションを更新Animation.animation(OPのその後端において示唆されるように)アニメーションに状態IDの簡単なルックアップを使用して、それに応じて)。明らかに、これはAnimationに依存しMovementます。

代替の構造はStateAnimation監視してMovement変更する一般的なコンポーネントを持つことです。これは基本的にはモデルビューコントローラ(この場合は状態アニメーション移動)です。

もう1つの方法は、状態が変化したときにエンティティにコンポーネントにイベントをディスパッチさせることです。Animationこのイベントをリッスンし、それに応じてアニメーションを更新します。これにより、依存関係がなくなりますが、依存バージョンはより透過的な設計であると主張できます。

幸運を。


したがって、アニメーションは状態を観察し、状態は動きを観察します...依存関係はまだ残っていますが、試してみるかもしれません。最後の代替案は次のようなものでしょうか:移動はエンティティへの変更を通知し、エンティティはStateにイベントをディスパッチし、StateとAnimationに対して同じプロセスが繰り返されますか?このアプローチはパフォーマンスにどのような影響を与える可能性がありますか?
miviclin

最初のケース:Movement制御 State(観察ではありません)。最後のケース:はい、そうMovementでしょうentity.dispatchEvent(...);。そのタイプのイベントをリッスンする他のすべてのコンポーネントがそれを受け取ります。もちろん、パフォーマンスは純粋なメソッド呼び出しよりも劣りますが、それほどではありません。たとえば、イベントオブジェクトをプールできます。ところで、エンティティを「イベントノード」として使用する必要はありません。専用の「イベントバス」を使用して、エンティティクラスを完全に除外することもできます。
Torious

2

問題について、STATEがアニメーションでのみ使用されている場合は、それを他のコンポーネントに公開する必要すらありません。複数の用途がある場合は、公開する必要があります。

あなたが説明するコンポーネント/サブシステムのシステムは、コンポーネントベースよりも階層ベースに感じられます。結局のところ、コンポーネントとして説明するのは、実際にはデータ構造です。それが悪いシステムであることを意味するのではなく、コンポーネントベースのアプローチにあまり適合しないと思うだけです。

お気づきのように、依存関係はコンポーネントベースのシステムでは大きな問題です。これに対処するにはさまざまな方法があります。一部のコンポーネントでは、依存関係を宣言して厳密なチェックを行う必要があります。その他は、特定のインターフェースを実装するコンポーネントを照会します。さらに、それぞれをインスタンス化するときに、依存コンポーネントへの参照を渡します。

使用するメソッドとは関係なく、コンポーネントのコレクションとして機能するには、何らかのゲームオブジェクトが必要です。GameObjectが提供するものは大きく異なり、頻繁に使用されるデータをGameObjectレベルにプッシュすることで、コンポーネント間の依存関係を簡略化できます。Unityは、たとえば変換を使用して、すべてのゲームオブジェクトに強制的に1つを持たせます。

さまざまなゲームオブジェクトのさまざまな状態/アニメーションについて尋ねる問題について、は次のようします。まず、私は実装のこの段階ではそれほど凝ったものにはなりません。動作させるために今必要なものだけを実装し、必要に応じてベルとホイッスルを追加します。

したがって、「State」コンポーネントから始めます。PlayerStateComponent、Enemy1State、Enemy2Stateです。状態コンポーネントは、適切なタイミングで状態を変更します。状態はほとんどすべてのオブジェクトが持つものなので、GameObjectに常駐できます。

次に、AnimationCompomentがあります。これには、状態に合わせたアニメーションの辞書があります。update()で、状態が変化した場合にアニメーションを変更します。

私が見つけられないフレームワークの構築についての素晴らしい記事があります。ドメインでの経験がない場合は、問題を1つ選び、現在の問題を解決する最も簡単な実装を行う必要があると述べています。次に、別の問題/ユースケースを追加して、フレームワークを拡張しながら、有機的に成長します。特にあなたがやっているように新しいコンセプトで作業するとき、私はそのアプローチが本当に好きです。

私が提案した実装は非常に素朴ですが、ユースケースを追加するにつれて、いくつかの改善点が考えられます。

  • GameObject変数を辞書に置き換えます。各コンポーネントはディクショナリを使用して値を格納します。(衝突を適切に処理するようにしてください...)
  • 代わりにプレーン値のディクショナリを参照で置き換えます。class FloatVariable(){public value [...]}
  • 複数の状態コンポーネントの代わりに、変数の状態マシンを構築できる汎用のStateComponentを作成します。キーの押下、マウス入力、変数の変更(上記のFloatVariableに関連付けることができます)のように、状態を変更できる一般的な条件のセットが必要です。

このアプローチは機能し、1年前に同様のものを実装しましたが、問題はほとんどすべてのコンポーネントが他のコンポーネントに依存しているため、柔軟性が低いようです。最も一般的なコンポーネント(例:変換、レンダリング、状態...)をエンティティにプッシュすることも検討しましたが、コンポーネントの一部はエンティティに関連付けられていて、一部のエンティティはコンポーネントを必要としない場合があるため、コンポーネントの目的が損なわれると思います。そのため、システムがロジックの更新を担当するように再設計して、コンポーネントが自分自身を更新しないため、コンポーネントがお互いについて何も知らないようにします。
miviclin

0

ADBの回答に加えて、http://en.wikipedia.org/wiki/Dependency_injectionを使用できますこれは、コンストラクタへの参照としてそれらを渡すことにより、多くのコンポーネントを構築する必要がある場合に役立ちます。もちろん、それらは相互に依存します(コードベースで必要な場合)。ただし、依存関係がセットアップされ、残りのコードが依存関係を知る必要がない1つの場所にすべての依存関係を配置できます。

このアプローチは、各コンポーネントクラスが必要なものまたは登録が必要な場所を要求し、依存関係注入フレームワーク(またはすべてを設定する場所、通常はアプリ)だけが誰が何を必要としているのかを知っているため、インターフェースを使用する場合にもうまく機能します。

単純なシステムの場合、DIまたはクリーンなコードを使用せずに済む可能性があります。RenderingSystemクラスは、静的に呼び出すか、少なくとも各コンポーネントで使用できるようにする必要があるように聞こえます。よりクリーンなアプローチに興味がある場合は、上記のDI wikiリンクのリンクを確認し、クリーンコードについて読んでくださいhttp : //clean-code-developer.com/


コンポーネントが相互にかなり依存している1つのシステムがすでにあります。そこで私は依存関係注入を多用しましたが、深い階層よりも優先していますが、可能であればコンポーネントの結合を回避するために新しい階層を作成しようとしています。静的には何も呼び出さないでしょう。すべてのシステムがアクセスできるComponentManagerがあり(すべてのシステムがそれへの参照を持っている必要があります)、RendererSystemはコンポーネントマネージャーからすべてのアニメーションコンポーネントを取得し、各アニメーションの現在の状態をレンダリングします。
miviclin 2012年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.