エンティティコンポーネントシステム-ゲームの進行


8

私はゲーム開発(プログラミングではなく)に非常に慣れていないので、世界間の通信を処理するための最良の方法を理解しようとしています。私が言っているのはこれです:

私はエンティティコンポーネントシステム(ECS)と、人々がさまざまなワールド/スペース(http://gamedevelopment.tutsplus.com/tutorials/spaces-useful-game-object-containers--gamedev-14091)の使用をどのように提案するかについて読んでいますゲームのサブセクション。たとえば、HUD、インベントリ、または戦闘/移動は、それぞれ異なるワールド/スペースを取得します(それらは異なるグラフィックスと基礎となるロジックを持っているためです)。

しかし、たとえば戦闘中など、別のスペース/ワールドによってヘルスが処理される場合、インベントリまたはHUDがプレーヤーのヘルスをどのように知っているのかと思いました。

これは、ゲームの進行状況にも適用されます。たとえば、NPCとのダイアログ(ダイアログはポップアップ画面であるため別のスペースになります)ですが、ダイアログで行われた選択(または状態)を他のスペース/ワールドにどのように伝えますか。 。または基本的に、さまざまなスペース/世界でのゲームの進行に影響を与える他のタイプのイベント(健康、マナ、クエスト、ダイアログ、戦闘、インベントリ、hudなど)

この種の設計をどのように処理するでしょうか?このような情報をすべて保持する(実装の)シングルトンオブジェクトが必要ですか?それは奇妙なことです。それは、components2回物事をしているように感じる(プログラミングのメインDRYに反対する)このシングルトンオブジェクトに各変更を伝える必要があるからです...

私はここでデザインの点で途方に暮れています。


---編集---

だから私はコメントで提案された他のいくつかの投稿を読んで、可能性についての一般的な考えを得ましたが、それらのそれぞれには、それらを正しくないようにする1つの大きな欠点があるようです。これらの欠点を解決する詳細を監督している可能性が非常に高いため、自由に修正してください。概要と、いくつかの質問に対する回答を示します。

スペース間でデータを「共有」する3つの主要なオプションが表示されます。ほとんどの投稿はシステム間でのデータ共有に関するものですが、システム間でのデータ共有にも同じことが当てはまると思います。

1.クエリ

:HUDワールドがプレーヤーの現在のヘルスを知る必要がある場合、HUDワールドは別のワールドを照会して現在のヘルスを要求できます。

欠点:世界はお互いを知る必要があります。これは依存関係の大きな問題であり、デカップリングに反対しています。

2:ダイレクトメッセージング(同期および非同期)

:戦闘中にプレーヤーのヘルスが変更された場合、この変更について知る必要がある他の世界にメッセージ(同期と非同期、必要なものは何でも)を送信できます。

欠点:それでもデカップリングの問題:世界はお互いについて知る必要があります。

3:間接メッセージング(同期および非同期) <-最適なオプション

:戦闘中にプレーヤーのヘルスが変化した場合、プレーヤーはメッセージ(同期と非同期、必要なものは何でも)を一般的なメッセージハブに送信できます。この変更について知る必要がある他の世界/システムは、特定のメッセージチャネルにサブスクライブされ、メッセージを読み取ります。

利点:完全に分離され、管理と拡張が容易です。

欠点/不明確:メッセージチャネルは、メッセージを削除する必要があることをいつ知っていますか?または、サブスクライブしているシステムがメッセージを(それ自体のみ)既読としてマークし、新しいメッセージを待つ->しばらくするとメッセージボックスが巨大になる。ワールド/システムはどのように順序を処理しますか?たとえば、フレーム中:HUDがすでにヘルスメッセージをポーリングし、その後ヘルスが変化した場合、次のフレームでHUDが更新されます。一部のアプリケーションでは、これは正しい方法ではない場合があります。

Q:1つのゲームオブジェクトが複数のスペースに存在できます

私は組み込みスペース(ワールドと呼ばれます)に付属しているArtemis ECSフレームワークを使用しています。各エンティティ(およびそれとともにコンポーネントの形式のデータ)はワールド上に作成されるため、ワールド間で共有することはできません。


ここでのメッセージングは​​標準的なアプローチです。gamedev.stackexchange.com
23834

リンクされた記事で私が読むことができるものから、単一のゲームオブジェクトが複数のスペースの下に存在する可能性があります。スペース間に異なるグラフィックまたはロジックがある場合は、データをグラフィックおよびロジックから分離します。スペース間でデータゲームオブジェクトを共有し、さまざまなグラフィックスおよびロジックゲームオブジェクトと集約します。
Andreas

:この答えは、私もあなたを助けることができるシステムをメッセージングについて与えたgamedev.stackexchange.com/questions/7718/...
ジェームズ

私はgamedevライフに3つのソリューション(クエリ、直接、間接)をすべて実装しました。そして、私にとっては3番目のオプションが最も効果的だと言えます。システムを簡単に分離し、それらのロジックを並行して実行できます。唯一の欠点は、1つのシステムから別のシステムにすべてのメッセージ/イベントをルーティングするために9つの関数呼び出しを実行する必要があることです。明らかに、それを最適化することができ、大きな利点は、このアプローチではミューテックスやシングルトンを必要としないことです。
グレゴリー

@グレゴリーあなたの入力をありがとう、私は間接的なメッセージが最良の選択肢であることを期待していました。私は9つの関数呼び出しを認識していませんでしたが、このメッセージハブを計画するときに、実際にはかなりの呼び出しになることがわかりました。システムがメッセージを必要としなくなったときに、メッセージを削除するための良い解決策/代替案を見つけたことがありますか?
ティム

回答:


1

これを確認する1つの方法は、ゲームオブジェクトに多くを入れすぎている可能性があることです。

実際にHUDをインワールドゲームにフックするコードが、特定の空間に存在するコンポーネント/システムにある必要がある理由はありません。そのコードは、おそらくすべてのスペースとすべてのオブジェクトにアクセスできる中央マネージャーまたはグローバルスクリプトに住む方が得策であり、実際にスペースを作成するタイミングとスペースに何を配置するかを知っているコード(コードなど)と対話できます。プレーヤーをスポーンしたり、レベル間の状態を保存したりします)。

レベルとUIに使用されるスペースを過去に維持したり操作したりする必要があるロジックまたはデータを含むゲームオブジェクトを保持する「マスタースペース」を用意することもできます。このアプローチは、開発者にすべてのスクリプト/ロジックをコンポーネント/オブジェクトに置くことを強制するエンジンでは一般的です(たとえば、Unityでは、グローバルMainオブジェクトを作成し、シーンのアンロード全体で永続化するように設定します。Unityに実際にスペースがある場合は、 dフラグの代わりにそれらを使用してください)。

ECSの悪用は設計パターンの悪用と同じです。気の利いた新しいツールがあるからといって、遭遇するすべての問題を解決するためにそのツールを使用することになっているわけではありません。90年代の暗い時代に祖先が使用していた古い薄汚いものであっても、問題のある空間を評価し、最適なソリューションを選択してください。:p


0

私はいくつかのプロトタイプを作成しましたが、大きすぎず、複数のスペースを処理するために使用した方法は、ワールド、プレーヤーなどを含むゲームオブジェクトを単に作成することでしたが、ヘルスなど、他のいくつかのスペースで必要なプロパティを設定しました。 、ゲームオブジェクト

呼び出されたときはいつでも、それはプレイヤーの健康を得ます。そうすれば、HUDに送信してヘルスバーを表示できます。

それは最もきれいではありませんが、それは仕事を成し遂げました、私は2013年にいくつかのパフォーマンステストを行いました、そしてすべてがスムーズに機能しているようでした。このような依存関係を回避するために、プレーヤーのヘルスがnullの場合は常にヘルスバーをドロップできます。

通常、プレーヤーが存在しない場合は、ユーザーがメニューまたはカットシーンにいることを意味します。

コード例:

public float PlayerHealth {
  get {
    if (player !+ null) 
      return player.Health;
    return -1;
  }
}

これがあなたが探していたものであることを願っています。


0

これは私が過去数週間で実際に取り組んでいるものです。私は自分のECSライブラリに取り組んでいます(経験上、それを試してみたかったので、かなり長い間そうしたかったので)。

これはgithubリンクです:https : //github.com/gioragutt/xna-ecs

あなたの問題のために、私はいつも小さなpubsubライブラリを書いてきました。

基本的に、私はEmsClientクラスがあり、そこから派生することができます。現在、私のコンポーネントはそれをしていませんが、理由はありませんが、より高いレベルのクラスです。Names of messagesをサブスクライブし、次の署名のコールバックを提供しますAction<JObject>。すでにご存じのとおり、私はメッセージを転送する手段としてJsonオブジェクトを使用しています。以前にちょうどを使用した後でこれbyte[]を実行しましたが、より一般的なものが必要であることがわかりました。私は職場でそのようなものに慣れているためです(コールバックを除いて同様に機能するIPCDがあります)メソッドは常に同じです。通常、異なるハンドラに対して責任を分離するためです)。

そのレルムEmsServerEmsClientでメッセージを移動する責任がある(サーバー上に1つと各クライアント上に1つ)がEmsServerあります(サーバー側ではサーバー側でメッセージを移動EmsClientsし、クライアント側ではその逆です)。

クライアントとサーバー間のメッセージングEmsServerEndpointでは、EmsClient自分自身を作成しました。彼は送信されたメッセージをそのレルムにバッファリングし、それらを他のレルムにフラッシュするロジックを実行します(FEはクライアントがサーバーにメッセージを送信しますが、サーバーは、接続されているすべてのクライアントに各メッセージを転送します。

あなたは多くの場所での使用を見ることができます、fe:ClientGameManagerServerGameManager

一方、例として、プレーヤーのGUIコンポーネントを追加する場合は、プレーヤーののビルドを担当するおよびメソッドをここで確認できます。それぞれに(ECS libからの)と(ECS libからの)が含まれています。それぞれが自動的に変換を取得します(のように、そこからインスピレーションを得ました)。BeginAllocateLocalBeginAllocateRemoteGameObjectsGameObjectEntityIComponentContainerGameObjectUnity

私のコードはそれ自体がほとんどを物語っています、そしてあなたがそれに到達した場合、私はそれに対する批判を探しているので、いくつかの建設的な批評をお願いします:)

私のコードがいくつかのアイデアであなたを助けることを願っています!


0

ゲームコンポーネントとUIコンポーネントのオブザーバー/サブジェクトパターンコンポーネントを検討してください。あなたは作成/ロード時にそれらを一緒に接続し、それらを忘れます。キャラクターの健康状態が変化すると、すべてのオブザーバーに通知されます。オブザーバーは、その情報を使用して何でも好きなことができます。

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