コンポーネントベースの設計における入力処理


12

この質問が何度も尋ねられたことは知っていますが、コンポーネントベースのエンジンで入力処理を実装する方法はまだわかりません。

私が使用したコンポーネントベースのデザインは、T = Machineのブログシリーズと、エンティティが単なるIDであるArtemisに基づいてました。

入力処理の実装には、主に3つのアイデアがあります。

  1. 入力コンポーネントは、関心のあるイベントを保持します。入力システムは、キーイベントとマウスイベントをゲームイベントに変換し、エンティティを入力コンポーネントとともにループします。イベントに関心がある場合は、入力システムによって適切なアクションが実行されます。このアクションは、入力システムにハードコーディングされます。
  2. 入力コンポーネントはありません。特定のイベントを持つエンティティを入力システムに登録します。次に、入力システムはメッセージ(エンティティIDとイベントタイプを含む)を他のシステムに送信し、これらが適切なアクションを実行できるようにします。または、最初のケースと同様に、アクションは入力システムにハードコーディングされます。
  3. 最初のメソッドと同様ですが、アクションを入力システムにハードコーディングする代わりに、コンポーネントにはstd::map<std::function>、入力システムによって呼び出される関数(つまり)へのイベントのマップが含まれます。これには、同じイベントを異なるアクションに結合できるという追加の効果があります。

上記の方法のいずれかをお勧めしますか、それとも柔軟な入力処理システムを実装するのに役立つ提案がありますか?また、私はまだマルチスレッドに精通していませんが、実装をスレッドフレンドリーにする提案があれば歓迎します。

注:実装が満たしてほしい追加の要件の1つは、たとえばカメラエンティティとプレーヤーを同時に移動するなど、同じ入力を多くのエンティティに渡すことができることです。


2
通常(カメラがプレーヤーに追随している場合)、カメラで入力を受け取りたくない場合は、代わりにカメラにプレーヤーの位置を確認させ、追従させます。
ルークB.

1
カメラがプレイヤーに追随するか、それとも「自分」に追随するかは、概念的には重要ではありません。それにもかかわらず、あなたの提案が、設計原理を壊すことなくコンポーネントベースの設計にどのように実装されるかはわかりません。
グリーバーハート、2013

1
@Luke B .:少し考えてから、カメラを別のクラスとして作成し、追跡するエンティティへのポインタを取得することもできると思います。
グリーバーハート2013

回答:


8

は、コンポーネントシステムの材料に関する私の回答と同じようにすべてを「コンポーネント」に押し込もうとしているという問題に直面していると思います。これを行う必要はありません。そうすることで、正方形のペグの束を丸い穴に合わせようとすることによって、本当に面倒なインターフェースを作成していることになります。

プレーヤーからの入力の取得を処理するシステムがすでにあるようです。次に、その入力をアクション(「前に移動」または「後ろに移動」)またはイベントに変換し、それらを関係者にディスパッチするアプローチを選択します。以前は、コンポーネントがこれらのイベントに自分自身を登録することを許可していませんでした。上位レベルのシステムが「制御されたエンティティ」を明示的に選択するアプローチを好んでいました。ただし、必要に応じて他の方法で機能することもあります。特に、入力によって直接刺激されなかったアクションを実行するために同じメッセージを再利用する場合はそうです。

ただし、カメラエンティティとプレーヤーエンティティの両方に "前進"(et cetera)メッセージに応答させることで、カメラ追跡動作を実装することは必ずしも推奨されません。これにより、2つのオブジェクト間に非常に堅固な接続が作成され、プレーヤーに不快感を与える可能性が高くなります。また、プレーヤーが左または右に回転するときにカメラがプレーヤーを周回させるなどの処理が少し難しくなります。エンティティがあります。プレイヤーにスレーブされていると想定して「左回転」に応答しますが、スレーブ化されていない場合は正しく応答できません...確認できる状態としてその概念を導入しない限り。そして、それを行うつもりなら、2つの物理オブジェクトを一緒にスレーブ化するための適切なシステムを実装し、適切な弾性の調整可能要素などを実装することもできます。

マルチスレッドに関しては、ここではそれを採用する必要はないと思います。それは価値があるよりも複雑になる可能性があり、本質的にシリアルの問題に対処しているため、多くのスレッドを関与させる必要があるだけです。同期プリミティブ。


私は自分の質問を考え、自分で答えようとしていました。また、ECシステムから入力処理を分離するほうがよいので、これを確認できるとうれしいです。これを行うために私がどのように考えたかは、信号の使用と、いくつかのエンティティをイベントタイプに関連付ける機能によるものです。また、カメラを分離することも決定しましたが、これは実際には必要ではなく、実体としても同様に実行可能です。ECの初心者である場合は、何かをコンポーネントまたはエンティティにすることの利点を実際に考える必要があると思います。
グリーバーハート2013

4

私の経験は偏っているかもしれませんが、マルチプラットフォームプロジェクトでは、入力デバイスがエンティティシステムに直接公開されていません。

入力デバイスは、キー、ボタン、軸、マウス、タッチサーフェス、加速度計からイベントを受け取る下位レベルのシステムによって処理されます...

これらのイベントは、コンテキストに依存する意図ジェネレーターのレイヤーを介して送信されます。

各ジェネレーターは、その機能に関連するコンポーネント、エンティティー、システムからの状態変化を登録します。

これらのジェネレーターは、エンティティがコンポーネントを持っている意図システムにルーティングするためのメッセージ/意図を送信するか、直接適切なコンポーネントに送信します。

このようにして、同じ入力、つまりJUMP_INTENT(1)、JUMP_INTENT(0)、AIM_INTENT(1)...を持つ「常に」に単純に依存できます。

そして、「すべての」ダーティプラットフォームに依存する入力作業は、エンティティシステムの外部に残ります。


カメラについては、プレーヤーの周りに移動したい場合は、独自のインテントコンポーネントを登録し、送信するインテントを聞くことができます。

それ以外の場合は、プレーヤーをフォローするときに、プレーヤー宛ての入力を聞いてはなりません。これは、プレーヤー(ENTITY_MOVED(transform))によって発行された状態の変化をリッスンし、それに応じて移動する必要があります。物理システムを使用している場合は、さまざまなジョイントの1つを使用してカメラをプレーヤーに取り付けることもできます。


コヨーテ、回答ありがとうございます。私はあなたの他の投稿もここで読んだ。私の最大の懸念は、入力をどのように抽象化するかではありません。キープレスなどを処理する下位レベルの構成要素が既にあり、もう1レベルの間接指定を追加することは難しくありません。私の問題は、たとえばインテントシステムによって生成されたイベントの処理にあります。私が正しく理解していれば、メソッドに入力コンポーネントがまったくありません。どのエンティティに入力が必要かをどのようにして把握し、それをどのように処理しますか?より具体的な例を挙げていただけますか?
グリーバーハート2013

2

InputComponentにはどのようなメリットがありますか?確かに、アクションを実行するエンティティを決定するのは、入力コマンドの特権です。典型的な例は、プレイヤーをジャンプさせることです。「ジャンプ」イベントをリッスンするすべてのエンティティにInputComponentを持たせる代わりに、ジャンプコマンドで「player」とマークされたエンティティを検索して、必要なロジック自体を実行してみませんか?

Action jump = () =>
{
    entities["player"].Transform.Velocity.Y += 5;
};

OPからの別の例:

Action moveRight = () =>
{
    foreach (var entity in entities.Tagged("player", "camera"))
        entity.Transform.Position.X += 5;
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.