コンポーネントベースのエンティティシステムでのゲームの状態と入力の処理


16

私の質問は:

ゲーム状態オブジェクトのスタックを保持することなく、エンティティシステムでゲーム状態を処理するにはどうすればよいですか?

したがって、エンティティシステムの設計とは、たとえばエンティティが入力イベントに登録する必要がある場合、入力コンポーネントが入力システムを呼び出し、「このエンティティをこの入力に登録する」と言うことです。これはすべて問題ありませんが、これにゲーム状態の概念(たとえば、一時停止画面)を追加すると、エンティティが現在の状態にあり、入力を受け取る必要がある場合に解決することが問題になります。

「これらのゲーム状態にあるときにこのエンティティをこの入力に登録する」と言うように入力コンポーネント/システムを拡張できますが、これにはすべてのエンティティがどの状態で使用されるかを知る必要があり、それは明らかではないかもしれません。また、登録された入力(およびコールバックを使用する他のシステム)ごとにゲームの状態のリストを保持することは、あまり効率的ではありません。

私が持っていた別のアイデアは、ゲーム状態を表すエンティティがあり、無効になっていることをマークし、入力イベントを生成するときに、そのエンティティが無効なゲーム状態エンティティの子孫ではないことを確認することです。コールバックごとに親を解決するのは費用がかかるようです。

別のアイデアは、すべてのシステムに現在の状態に対してキー設定されたデータを保存させることです。そうすることで、入力を生成するときに、ターゲットエンティティは候補にさえなりません。しかし、これは異なる状態のエンティティ間の通信を許可する機能を本当に損ないます(一時停止画面ではそれほど問題ではありませんが、Oblivion / Skyrimでのロック選択を考えてください)。

私が持っていた唯一の他のアイデアは、すべてのコンポーネントが状態変更イベントを処理し、関連するシステムと通信して登録済みのものを無効にし、この状態に戻るときに再び有効にすることです。

2番目(オブジェクトを無効としてマークする)と4番目(各コンポーネントが状態の変更を処理する)は、私のアイデアの中で最高のように見えますが、特に素晴らしいと思うものはありません。

他の誰かがこれを行う方法について他のアイデアを持っていますか?

編集この質問では特に入力について説明しますが、衝突、タイマーイベントなど、エンティティにメッセージ/イベントを送信できるシステムを意味します。


6
私はこのようにします:Screen、MenuScreen PauseScreen GameScreenがあり、各画面は独自のワールド(エンティティのコンテナ)とシステム(RenderingSystemなど)を作成し、GameScreenでWorld、CameraComponentを持つエンティティを作成し、CameraComponent.RenderTargetを設定します画面の背景。この方法で、独自のエンティティとシステム(簡易レンダラーなど)を持つInventoryScreenを追加できます。(などその焦点を当て、可視の場合)、それが画面に入力を通過し、それが世界とエンティティに入力を渡す場合は、あなたのユーザインタフェースが決定しますので、入力は、画面から世界に渡すことができます
Kikaimaru


2
@ Byte56実際には、最初の1つだけがゲーム状態に関係し(他の2つはエンティティ内の状態です)、それは実際に私が抱えているのと同じ問題に取り組んでいません。ゲームが一時停止状態にある場合、入力システムに何かが発生して、プレイヤーエンティティへの移動メッセージの送信を停止する必要があります(たとえば)、これを行う良い方法がわかりません。
elFarto

1
OK、それらを関連することを考慮してください。良い質問。
マイケルハウス

1
過去に私のコンポーネントベースのシステムに迷惑をかけていたことを考慮に入れるべき他の何か:マルチレイヤーUI。ワールドまたはマルチレベル画面の上部に表示されるダイアログ。これまでに私が作ったすべてのゲームでそれが出てきたので、私はその問題を解決できるアプローチを検討することを確実にするように言いたいと思います。
ADB

回答:


14

よく使用されるのはIntent System、入力を抽象化し、コンテキストと関連するゲーム状態を追跡する中間体です。

Intentシステムは、たとえばシミュレーションが一時停止すると入力の送信を停止します。また、コントローラーイベントとインテント(方向の移動、実行、撮影、再読み込みなど)間のマッピングも処理します。

このように、他のコンポーネントは特定のゲームパッド/入力(BUTTON_A、BUTTON_B対BUTTON_X、BUTTON_O ...)に依存しませんが、それらはすべて同じインテント(IntentRun、IntentReload ...)に反応します。

別の利点は、インテントシステムが追加/削除されている利用可能なコントローラーを認識できることです。これは、インテントを処理できるシミュレーション以外でもインテントを任意のサブスクライバーに送信できるためですAddPlayer(controllerID)

イベント/メッセージを介して、または直接システムに提供するゲームの状態に関する情報は、ユーザー次第です。しかし、Intentシステムに費やす時間は、通常は価値があります。

インテントコンテキストを管理して、システムにアタッチされたときにインテントを生成できます。

コンテキストに優先順位を付けることができます。つまり:

  • SimulationAvailableContextは、カメラの移動、ズームイン、ズームアウト、プレーヤーの追加/削除など、使用可能な(ただし実行されていない)シミュレーションの意図をシミュレーションに送信します...
  • SimulationRunningContextは、一時停止されていない状態でシミュレーションに意図を送信し、プレイヤーの移動、ユニットの位置への送信、シュート...

この方法で、現在関連しているコンテキストを追加および削除できます。

そして、インテントシステム全体に関する1つのことは、シミュレーションが一時停止している間に実行する必要があるということです。

シミュレーションに関連しない更新を中断せずにゲームシミュレーションをプレイ/一時停止するためによく使用される1つの方法は、異なる時間セットを使用することです。すなわちGenericSystem::onTime(Long time, Long deltaTime, Long simTime, Long simDeltaTime)

このアプローチでは、あなたのエンジンは、単に順番に使用し、関連するアニメーション&物理エンジンの更新をブロックしますどのゲームのsimTimeに増分をブロックすることができsimTime and simDeltaTime、お使いのカメラのスプリング効果の継続的な更新を可能にしながら、それも一時停止中に移動しなければならない場合のアニメーションをデータのダウンロード中の仮想ゲーム内ビルボードへのローディング効果...


これは、すべてのエンティティで多数の「State Changed」関数を呼び出す必要がないという事実が気に入っています。間違った意図が間違ったタイミングで送信されることを心配する必要がありますが、他の方法よりも優れていると思います。
トーマスマーネル

エンティティは、ジャンプなどのインテントを無視できますが、その状態ではジャンプできません(地面に触れない)。しかし、ゲームが一時停止している間にそのような意図を受け取ることを心配する必要はありません。
コヨーテ

エンティティに入力システムにメッセージを配信する状態を伝えることは既に考えていましたが、入力自体に状態を置くことは考えていませんでした。これは良い考えです。また、時間とsimTimeを分けることも良いことです。
-elFarto

シミュレーションに関連しない状態で、シミュレーションに関連する状態を肥大化させないでください。すべてのUIを移動し、プレーヤー関連コードをシミュレーション自体からできるだけ遠くに移動し、シミュレーションではインテントのみに集中します。
コヨーテ

@Coyoteさん、このシステムは非常に興味深いですね。この質問に答えてさらに情報を提供していただけますか?ありがとう!
ペク

2

グローバルイベントシステムを作成してから、各エンティティのイベントリスナーコンポーネントを作成するのはどうでしょうか。イベント「Game State Change」の後、特定のエンティティごとに個別にコンポーネントをいじることができます。

入力コンポーネントがあるとします。イベントリスナーコンポーネントは、ゲーム状態変更イベントを受信すると、その特定の入力コンポーネントの非常に特定の値を変更するため、入力呼び出しを受信したり、システムまたはその所有者に対して移動または応答呼び出しを行ったりしません。

私のほとんどのコンポーネントはスクリプト化されているため(Lua経由)、これは私にとってはうまくいきます。つまり、キーが押されて動き+方向が発動すると一度トリガーされ、その後、キーが放されて停止+方向が発動するとトリガーされる入力コンポーネントがあります。また、イベントリスナーコンポーネントがあり、入力コンポーネント(ゲームが一時停止している場合)にアクセスして、関数の実行を停止し、必要に応じて停止します。その後、別のスクリプトを使用して、同じイベントとキー押下に対する異なる反応を持つ別のエンティティを簡単に追加できました。この方法では、異なる状態の異なるエンティティ間の相互作用を保存し、さらにカスタマイズしやすくします。さらに、一部のエンティティにはイベントリスナコンポーネントさえ含まれていない場合があります。

先ほど説明したのは、基本的に4番目のソリューションの実用的な例です。

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