私はさまざまなデザインパターン、その長所、短所、主な使用法などについてたくさん読んでいます。しかし、私は実験して自分の実装方法を考案したいと思っています(たとえそれらが最良でなくても)。現在、エンティティコンポーネントシステムの実装に問題があります。
このパターンの長所にもかかわらず、私は自分のやり方でいくつかのことをしたいと思っています。例えば:
1。)コンポーネントは、データ操作のために、より大きなインターフェイスにラップされます。ほとんどの場合、ECSコンポーネントにはデータのみが含まれている必要があり、システムはその主要なマニピュレーターであると読みました。私のシステムでは、コンポーネントのラッパークラスを使用するつもりです。
小さな例:ゲーム内の各エンティティのビジュアルコンポーネントを表すSpriteコンポーネントが必要だとしましょう。エンティティのコンポーネントになり、追加の関数と変数を持つことができるRenderableEntityクラス内にラップしました。
2。)すべてのタイプのコンポーネントにシステムを使用するわけではありません。
再びゲームエンジンの例:いくつかの空間データ構造に配置され、その衝突チェックを行うCollidableEntityがありますが、RenderableEntityにはそれを管理するシステムがありません(私は現在は2Dです)。理由?特定の順序または異なるバッチを使用するため、各エンティティのスプライトをレンダリングする能力をユーザーに持たせたいです。
。)エンティティは同じタイプのコンポーネントを複数持つことができ、システムが特定のエンティティに関心があるかどうかをチェックするためにビットセットは使用されません。コンポーネントは、データ型を介して作成時にシステムに割り当てられます。
小さなコード:
template<class DataType>
DataType* createComponent(GameEntity* mainEntity)
{
//Create it via default constructor
DataType* component = new DataType();
//Add it to the back of the component vector
mainEntity->_entityComponents.emplace_back(component);
//Assign it to system
ECS::assignToSystem<T>(component);
//Return it to access its functions
return component;
}
AssignToSystem関数は次のことを行います。マップ内の指定されたデータ型かどうかをチェックし、そうでない場合はコンポーネントをシステムに追加し、今後はシステムがコンポーネントの管理者になります。また、ゲームシステムは関数を介して特定のデータ型に接続され、次のようになります。
class ColliderSystem:public ECS::System
{
void assignSystem() override
{
ECS::assignSystemToComponent<CollidableEntity>(this);
}
};
与えられたパターンを試し、自分のやり方でやってみるのが良いアイデアかどうか教えていただけますか卒業制作でこのアプローチを使用し、いくつかのパターンの「ルールを破る」ことが問題になるのではないかと考えているので、特に私はこれを気にします。また、私の「変更」についてどう思いますか、何か短所はありますか?ありがとう。
人々は、過去にデザインパターンを実装するさまざまなメカニズムを試し、さまざまな結果を得ました。たとえば、singletonの定義は、アプリケーション全体でクラスのインスタンスが1つしかないことです。 GoFブックの例がそのように記述されている場合でも、静的アクセサーを使用して実装する必要がある定義はありません。 Springフレームワークなどのコンポーネントを使用する人々は、コンポーネントコンテナーがインスタンスが1つだけであることを保証し、そのインスタンスへの参照がアクセスが必要なすべての場所に注入されます。
その例はいくつかのポイントにつながります:
結局のところ、flyweightパターンの賢明な使用を称賛したり、どこかでデコレータパターンを使用したことを知っているユーザーはいません。パターンと呼ばれるのは、非常によく似た実装を持つ偶発的な問題の一般的な解決策だからです。多くの場合、実装の詳細は、それを生み出したコンセプトよりも重要ではありません。自分のコードが他の誰か、または3か月先の将来の自分にも理解できることを確認してください。
私は説教をするつもりはありませんが、あなたがしていることの影響をできるだけ客観的に見ることをお勧めします。ユーザーはapplication/game/tool/etcだけを気にします。動作します。チームの開発者は、それを理解して問題点を見つけたときに修正できるかどうかを気にします。標準から逸脱するたびに、コードを理解するのにかかる時間が長くなります。十分に煩わしいものにすると、開発チームがすべてを書き直して、より親しみやすくなります。
デザインパターンはビルディングブロックではありません。それらを使って「実験」しようとしている場合、おそらく意味のない状況でそれらを適用しようとしているでしょう。
代わりに、多種多様な問題を解決する多種多様なプログラムを構築してみて、実験する必要があります。そうすることで、いくつかのプログラムで使用したさまざまな手法が他のプログラムと類似していて、両方に適用できることがわかります。これらの類似点は、デザインパターンの概念が生まれた場所ですが、ビルディングブロックとしてではなく、用語として生まれました。
名前付きパターンが解決に役立つと認識された問題を知らない限り、それらを認識して、どのパターンが役立つかを知ることはできません。これらの問題を学ぶ唯一の方法は、さまざまな問題領域に取り組むことです。
デザインパターンは、ソフトウェア-- ジョイストハンガー に相当します。ジョイストハンガーは、構造のフレームメンバーを一緒に取り付けるために使用する鍛造金属片です。ジョイストをフレーミングに取り付けることはごくありふれた活動であり、何年もの間、誰もがそれを行うだけでした。
現場の大工が「ジョイストハンガーを試すのは良い考えですか?」彼らは2x4で頭を打たれるでしょう。デザインパターンと同様に、ジョイストハンガーは目的を達成するための手段であり、その目的を理解することが重要です。ジョイストハンガーを使用するようにデザインを作成するのではなく、ハンガーを使用します。ハンガーは強力な構造ジョイントの作成に役立つためです。
Simpson Strong-Tieカタログの完全な知識は、木製の構造物が最初にどのように組み合わされるかをほとんど視覚化できない限り、誰かにとって役に立たないでしょう。同様に、ソフトウェア設計パターンの場合、最初に完全なソリューションを構築する方法を最初に想定できる必要があります。
質問のECS固有の部分に取り組みます。より一般化された質問にはすでに素晴らしい答えがあります。
コンポーネントは、データ操作のために大きなインターフェースにラップされます。ほとんどの場合、ECSコンポーネントにはデータのみが含まれている必要があり、システムはその主要なマニピュレーターであると読みました。私のシステムでは、コンポーネントのラッパークラスを使用するつもりです。
私が最初に始めたときと同じことをしたのは、OOPのような情報の隠蔽やカプセル化などのすべての概念に挑戦したECSの私にとって最も異質な側面は、コンポーネントが生データであるという考えでした。いくつかのコンポーネントに抽象インターフェースを継承させるようなことから始め、それでもコンポーネントレベルでポリモーフィズムなどを適用しようとしました。
私のシステムが進化するにつれ、実際にはますます邪魔になることがわかりました。私のシステムでは、コンポーネントの内部に低レベルの方法でアクセスして、それらを耕して並列に変換し、同様にスカラーロジックで個別に変換できるようにしたいと考えていました。また、継承によってポリモーフィズムが必要ないことに気づきました。 ECSは基本的に、C++テンプレートと同じレベルの柔軟性のダックタイピングを通じて機能し、正式な継承階層を定義する必要はありません。何かhasモーションコンポーネントの場合、移動できます。
不変条件を維持するためにコンポーネントを不透明以上のものとして扱うことができるシステムの数を制限することで、システムに表示されるコンポーネントフィールドのスコープを縮小し、その方法で情報を隠すことができます。一部のコンポーネントでは、単一のシステムがその状態を変更できるようにするだけで意味がある場合があります。コンポーネントを個別のパブリックおよびプライベートインターフェイスとフィールドを持つ本格的なクラスに変える以外の方法で、このポリシーを適用できます。
多くの人がECSのこの側面について話をしていませんが、個人的に私にとってECSの最大の利点は、実際にはシステムを簡素化することでした。 20のシステムを持つエンジンについては、その背後にいくらか複雑な実装があっても、内部に機能を備えた100種類の小さなものが相互に作用しているシステムよりも、それらの機能が単純であっても、はるかに簡単です。 ECSの依存関係をプロットすると、コンポーネントから他のコンポーネントへのコンポーネントやシステムへのコンポーネントではなく、システムからコンポーネントへの矢印だけで、それは笑えるほど簡単です。機能を備えたシステムがシステムだけではない場合、これらの利点の多くが失われます。
2.)すべてのタイプのコンポーネントにシステムを使用するわけではありません。
コンポーネントに機能を提供したいのであれば、それは自然な傾向です。現在、彼らはシステムの責任をある程度混同しています。通常のECSでは、システムは機能を提供する唯一のシステムであり、理由のために、上記で説明したのと同じパスをたどる場合に感謝するようになります。
3.)エンティティは、同じタイプの複数のコンポーネントを持つことができます[...]
繰り返しますが、同様の誘惑がありました。ただし、これにより、コンポーネントタイプに基づいて操作を効果的に表現できなくなります。私はもはや言うことはできません"ボーンとモーションコンポーネントを持つシステム内のすべてのエンティティを私に与えてください。"少なくとも、私はマインドセットをもっと好きに変える必要があります、 "*与えるシステム内の少なくとも1つボーンおよびモーションコンポーネントを持つすべてのエンティティ。*
これは大したことではないように思えるかもしれませんが、エンティティ関連の操作の観点から、骨コンポーネントインスタンスの考えを骨コンポーネントタイプから分離する必要があるという点で、複雑さが増します。次に、すべてのシステムは、特定のエンティティーに接続されたすべての可能なコンポーネントタイプのコンポーネントの数が可変である可能性があるという前提で機能する必要があります。設計の複雑さが各システムの隅々にまで及んでいるため、この複雑さは価値があるよりも厄介であることがわかりました"物理システムが2つ以上のモーションコンポーネントを持つエンティティで何をすべきか? "。これらの質問に対する簡単な答えを思い付くことができたとしても、そのような設計がすべての単一のシステムで非常に多くの質問(ユーザーエンドと技術の両方)を引き起こすという事実は、それがワームの缶であるというサインです。
代わりに、skeleton
コンポーネントではなく1つ以上のボーンで構成されるbone
コンポーネントのように、実際に特定のコンポーネントタイプ自体を集合体にすることができます。システムを一般化して同じタイプのコンポーネントインスタンスを単一のエンティティにアタッチできるようにする代わりに、コンポーネントタイプ自体を集約することができます。
とにかく、あなたはこのように逸脱することによってあなたの目的のために何か素晴らしいものを思いつくことができるかもしれませんが、これらのパターンが勝手に発生したのではないことを知っています。 ECSアプローチは現在広く適用されているため、人々はあなたがECSアプローチで解決する必要があった同じ代替案を探求した可能性があります。後知恵は、他の方法では何もしません。
パターンは、特定の目的を達成するのに適していることが判明した設計アプローチを適用することにより、目標を達成するのに役立ちます。
もちろん、実験は自由です。
ただし、注意してください。卒業作業には、規律と正確さが必要です。したがって、既存のパターンのように新しいパターンを呼び出さないでください。レビュー担当者は、これを創造性ではなく知識不足と解釈する場合があります。
したがって、何か新しいものがある場合は、新しい名前を付けて、次のような実績のあるデザインパターンテンプレートを使用して卒業レポートで公開します。