タイトルは意図的に双曲線であり、それは単にパターンに不慣れなだけかもしれませんが、ここに私の推論があります:
エンティティを実装する「通常の」またはほぼ間違いなく簡単な方法は、それらをオブジェクトとして実装し、共通の動作をサブクラス化することです。古典的な問題へのこのリードは、「あるEvilTree
のサブクラスTree
かEnemy
?」。多重継承を許可すると、ダイヤモンドの問題が発生します。私たちは、代わりの複合機能を引く可能性Tree
とEnemy
、さらにその神クラスへのリード線の階層までを、あるいは我々は意図的に私たちの中での行動を残すことができますTree
し、Entity
そのことをクラス(彼らは極端なケースではインターフェースを作る)EvilTree
自体ことを実装することができます-どのリードにコードの重複がある場合SomewhatEvilTree
。
Entity-Component Systemsは、Tree
およびEnemy
オブジェクトを異なるコンポーネント(たとえばPosition
、Health
および)に分割してこの問題を解決し、AIの決定に従ってEntitiyの位置を変更するAI
システムなどを実装しようとしますAISystem
。これまでのところは良いですがEvilTree
、パワーアップを獲得してダメージを与えることができたらどうでしょうか?まず、a CollisionSystem
とa が必要ですDamageSystem
(おそらくこれらはすでにあるでしょう)。CollisionSystem
通信するために必要なDamageSystem
二つのものが衝突するたび:CollisionSystem
にメッセージを送信しDamageSystem
、それが健康を引くことができるようにします。ダメージもパワーアップの影響を受けるため、どこかに保存する必要があります。PowerupComponent
エンティティにアタッチする新しいものを作成しますか?しかし、その後DamageSystem
むしろ何も知らない何かについて知る必要があります-結局のところ、パワーアップを拾えないダメージを与えるものもあります(aなどSpike
)。この回答と同様のダメージ計算にも使用されるPowerupSystem
を修正するStatComponent
ことはできますか?しかし、現在では2つのシステムが同じデータにアクセスしています。ゲームがより複雑になると、多くのシステム間でコンポーネントが共有される無形の依存関係グラフになります。その時点で、グローバルな静的変数を使用して、すべての定型文を取り除くことができます。
これを解決する効果的な方法はありますか?私が持っていた1つのアイデアは、コンポーネントに特定の機能を持たせることでした。たとえばStatComponent
attack()
、デフォルトでは整数を返すだけですが、パワーアップが発生したときに構成できます:
attack = getAttack compose powerupBy(20) compose powerdownBy(40)
これはattack
、複数のシステムがアクセスするコンポーネントに保存しなければならない問題を解決しませんが、少なくともそれを十分にサポートする言語があれば、関数を適切に入力できます。
// In StatComponent
type Strength = PrePowerup | PostPowerup
type Damage = Int
type PrePowerup = Int
type PostPowerup = Int
attack: Strength = getAttack //default value, can be changed by systems
getAttack: PrePowerup
// these functions can be defined in other components or in PowerupSystems
powerupBy: Strength -> PostPowerup
powerdownBy: Strength -> PostPowerup
subtractArmor: Strength -> Damage
// in DamageSystem
dealDamage: Damage -> () = attack compose subtractArmor compose hurtSomeEntity
この方法で、少なくともシステムによって追加されたさまざまな機能の正しい順序を保証します。いずれにせよ、私はここで関数型リアクティブプログラミングに急速に近づいているようですので、代わりに最初からそれを使用するべきではなかったかどうかを自問します(FRPを調べただけなので、ここで間違っているかもしれません)。ECSは複雑なクラス階層よりも改善されていると思いますが、それが理想だとは思いません。
これを解決する方法はありますか?ECSをよりきれいに分離するために欠けている機能/パターンはありますか?FRPはこの問題に厳密に適していますか?これらの問題は、私がプログラムしようとしているものの固有の複雑さから生じているのでしょうか。つまり、FRPには同様の問題がありますか?