メモリ優先: 目立った違いはありません。タイルのテクスチャをロードする必要があります。テクスチャは、マップ + タイルのメモリの少なくとも 99% を占めます。それだけです。
テクスチャの再利用: テクスチャは自動的に再利用/キャッシュされます。同じテクスチャを使用する 2 つのスプライトは、それぞれが独自のテクスチャのコピーを持つのではなく、同じテクスチャを参照します。
フレームレート/バッチ処理:これは、適切なバッチ処理に関するすべてです。スプライト キットは、ノードの子を子配列に追加された順序でレンダリングすることにより、ノードの子をバッチ処理します。次の子ノードが前のものと同じテクスチャを使用している限り、それらはすべて 1 つの描画呼び出しにまとめられます。おそらく最悪のことは、スプライト、ラベル、スプライト、ラベルなどを追加することです。同じテクスチャを連続した順序で使用して、できるだけ多くのスプライトを追加する必要があります。
Atlas の使用法: ここで最も多くの賞金を獲得できます。一般的に、開発者はアトラスを分類しようとしますが、これは間違った方法です。タイル (およびそのアニメーション) ごとに 1 つのアトラスを作成する代わりに、できるだけ多くのタイルを含むテクスチャ アトラスをできるだけ少なく作成する必要があります。すべての iOS 7 デバイスで、テクスチャ アトラスは 2048x2048 にすることができ、iPhone 4 と iPad 1 を除いて、他のすべてのデバイスは最大 4096x4096 ピクセルのテクスチャを使用できます。
このルールには例外があります。たとえば、非常に大量のテクスチャがあり、すべてのデバイスのメモリに一度にロードできない場合などです。その場合は、最善の判断を下して、メモリ使用量とバッチ処理効率の適切な妥協点を見つけてください。たとえば、1 つの解決策は、別のシーンの他のテクスチャ アトラスでいくつかのタイルを複製することを意味する場合でも、一意のシーンごとに 1 つまたは 2 つのテクスチャ アトラスを作成することです。ほとんどの場合、どの風景にも表示されるタイルがある場合、それらを「共有」アトラスに配置することは理にかなっています。
タイルのサブクラス化に関しては、私はノード クラスのサブクラス化を避けることを強く支持します。特に、それらをサブクラス化する主な理由が、使用/アニメーション化するテクスチャを単に変更することである場合。スプライトはすでにテクスチャのコンテナであるため、スプライト テクスチャを変更して外側からアニメーション化することもできます。
データまたは追加のコードをノードに追加するには、独自の NSMutableDictionary を作成し、必要なオブジェクトを追加することで、その userData プロパティを熟読できます。典型的なコンポーネントベースのアプローチは次のようになります。
SKSpriteNode* sprite = [SKSpriteNode spriteWithWhatever..];
[self addChild:sprite];
// create the controller object
sprite.userData = [NSMutableDictionary dictionary];
MyTileController* controller = [MyTileController controllerWithSprite:sprite];
[sprite.userData setObject: forKey:@"controller"];
次に、このコントローラー オブジェクトは、タイルに必要なカスタム コードを実行します。タイルなどをアニメーション化することができます。唯一の重要な点は、所有ノード (ここではスプライト) への参照を弱参照にすることです。
@interface MySpriteController
@property (weak) sprite; // weak is important to avoid retain cycle!
@end
スプライトは辞書を保持するためです。ディクショナリはコントローラーを保持します。コントローラーがスプライトを保持する場合、スプライトへの保持参照がまだ存在するため、スプライトの割り当てを解除できませんでした。したがって、スプライトを保持するコントローラーを保持する辞書を保持し続けます。
コンポーネントベースのアプローチを使用する利点 ( Kobold Kitにも好まれ、実装されています):
- 適切に設計されていれば、任意または複数のノードで動作します。ある日、ラベル、効果、シェイプ ノード タイルが必要になったらどうしますか?
- すべてのタイルにサブクラスは必要ありません。一部のタイルは単純な静的スプライトの場合があります。したがって、それらには単純な静的 SKSpriteNode を使用してください。
- 必要に応じて、個々のアスペクトを開始/停止または追加/削除できます。当初は期待していなかった、または特定の側面が必要なタイルであっても。
- コンポーネントを使用すると、他のプロジェクトで頻繁に必要になる可能性がある機能のレパートリーを構築できます。
- コンポーネントは、より優れたアーキテクチャを実現します。古典的な OOP 設計の誤りは、Player クラスと Enemy クラスを持ち、両方が矢を放って鎧を装備できる必要があることに気付くことです。そのため、コードをルートの GameObject クラスに移動して、コードをすべてのサブクラスで利用できるようにします。コンポーネントを使用すると、機器と射撃コンポーネントを必要なオブジェクトに追加するだけです。
- コンポーネントベースの設計の大きな利点は、個々の側面の開発を他のものとは別に開始できるため、必要に応じて再利用したり追加したりできることです。異なる考え方で物事に取り組むので、ほとんど自然により良いコードを書くことができます。
- そして、私自身の経験から、ゲームをコンポーネントにモジュール化すると、バグがはるかに少なくなり、他のコンポーネントのコードを見たり検討したりする必要がないため、解決が容易になります。つまり、渡された値は、他のコンポーネントが引き継いだときにまだ正しいですか? そうでない場合、バグは最初のコンポーネントにあるはずです。
これは、コンポーネント ベースの設計に関する優れた入門書です。ハイブリッド アプローチは確かに進むべき道です。コンポーネントベースの設計に関するその他のリソースがありますが、「受け入れられた回答の著者」が示唆するように、パスから外れて FRP を検討しないことを強くお勧めします。FRP は興味深い概念ですが、ゲーム開発における実際のアプリケーションは (まだ) ありません。