これまでのところ、私が使用したエンティティコンポーネントシステムは、ほとんどがJavaのアルテミスのように機能しています。
- コンポーネント内のすべてのデータ
- ステートレスな独立したシステム(少なくとも初期化時に入力を必要としない程度)は、特定のシステムが関心のあるコンポーネントのみを含む各エンティティを反復します。
- すべてのシステムはエンティティを1ティック処理し、その後すべてをやり直します。
今、私はこれをターンベースのゲームに初めて適用しようとしています。ゲームを進める前に、相互に設定された順序で発生しなければならない大量のイベントと応答があります。例:
プレイヤーAは剣からダメージを受けます。これに応じて、Aの鎧はキックインし、受けるダメージを減らします。Aが弱まる結果、Aの移動速度も低下します。
- 受けたダメージは相互作用全体を開始するものです
- ダメージがプレイヤーに適用される前に、鎧を計算して、受けたダメージに適用する必要があります
- 移動速度低下は、最終的なダメージ量に依存するため、実際にダメージが与えられるまでは適用できません。
イベントは他のイベントをトリガーすることもできます。鎧を使用して刀のダメージを軽減すると、刀が粉砕され(これはダメージの軽減が完了する前に行う必要があります)、次に、それに応じて追加のイベントが発生し、本質的にはイベントの再帰的な評価が発生します。
全体として、これはいくつかの問題につながるようです:
- 多くの無駄な処理サイクル:ほとんどのシステム(レンダリングのように常に実行されるもののために保存)は、「自分の番」が機能しない場合に実行する価値のあることは何もなく、ほとんどの時間はゲームの開始を待機しています。有効な作業状態。これにより、そのようなすべてのシステムに、ゲームに追加される状態が増えるにつれてサイズが大きくなり続けるチェックが散らばっています。
- システムがゲームに存在するエンティティを処理できるかどうかを確認するには、他の無関係なエンティティ/システムの状態を監視する何らかの方法が必要です(ダメージの処理を担当するシステムは、鎧が適用されているかどうかを知る必要があります)。これは、複数の責任でシステムを混乱させるか、または各処理サイクルの後にエンティティコレクションをスキャンし、何かをする準備ができていることを通知することによって一連のリスナーと通信する以外に目的のない追加のシステムの必要性を生み出します。
上記の2つのポイントは、システムが同じエンティティセットで動作し、コンポーネントのフラグを使用して状態が変化することを前提としています。
それを解決する別の方法は、単一のシステムがゲームの状態を進行させるために動作する結果として、コンポーネントを追加/削除する(または完全に新しいエンティティを作成する)ことです。これは、システムが実際に一致するエンティティを持っている場合はいつでも、処理が許可されていることを認識していることを意味します。
ただし、これにより、システムは後続のシステムのトリガーを担当し、単一のシステムの相互作用の結果としてバグが表示されないため、プログラムの動作を推論することが難しくなります。新しいシステムを追加することは、他のシステムにどのように影響するかを正確に把握しないと実装できないため(そして以前のシステムを変更して、新しいシステムが関心のある状態をトリガーする必要がある場合があるため)、さらに難しくなります。単一のタスクで。
これは私と一緒に暮らす必要があるでしょうか?私が見たすべてのECSの例はすべてリアルタイムであり、そのような場合にこのゲームごとの1回の繰り返しがどのように機能するかを確認するのは非常に簡単です。そして、私はまだレンダリングにそれを必要とします、何かが起こるたびにそれ自身のほとんどの側面を一時停止するシステムには本当に不適当に思えます。
これに適したゲームの状態を進めるためのデザインパターンはありますか?それとも、すべてのロジックをループの外に移動し、代わりに必要なときにのみトリガーする必要がありますか?