このページでは、UnityプロジェクトでScriptableObjectベースのenumを使用する方法を説明します。
本書は、電子書籍に付属するデモでUnity開発者を支援するために作成された6つのミニガイドシリーズの第3弾です、 UnityでScriptableObjectsを使用してモジュラーゲームアーキテクチャを作成する.
このデモは、古典的なボールとパドルを使ったアーケード・ゲームのメカニズムにインスパイアされたもので、ScriptableObjectが、テスト可能でスケーラブル、かつデザイナーフレンドリーなコンポーネントの作成にどのように役立つかを示しています。
電子書籍、デモプロジェクト、そしてこれらのミニガイドを合わせると、UnityプロジェクトでScriptableObjectクラスを使用してプログラミングデザインパターンを使用するためのベストプラクティスが提供されます。これらのヒントは、コードを単純化し、メモリ使用量を減らし、コードの再利用性を促進するのに役立つ。
このシリーズには以下の記事が含まれる:
ScriptableObjectのデモ・プロジェクトやこの一連のミニ・ガイドに飛び込む前に、デザイン・パターンの核心は単なるアイデアに過ぎないということを覚えておいてほしい。すべての状況に当てはまるわけではない。これらのテクニックは、UnityとScriptableObjectの新しい使い方を学ぶのに役立ちます。
それぞれのパターンには長所と短所がある。特定のプロジェクトに有益なものだけを選ぶ。デザイナーはUnity Editorを多用していますか?ScriptableObjectベースのパターンは、開発者とのコラボレーションを助ける良い選択かもしれない。
結局のところ、最良のコード・アーキテクチャとは、あなたのプロジェクトとチームに合ったものなのだ。
列挙型は、コード内で固定された名前付き値のセットを管理する便利な方法です。しかし、これにはいくつかの制限がある。直列化された列挙型の値は、シンボル名ではなく整数として格納されるため、値を削除したり並べ替えたりすると、正しくない動作や予期せぬ動作につながる可能性があります。つまり、列挙型(enum)は、特にその数が多い場合、Unity開発において頭痛の種になる可能性があるということです。
標準的なアプローチ
典型的な列挙型はこんな感じだ:
[System.Serializable]
public enum ハンドジェスチャー
{
ロックだ、
論文
はさみ
}
System.Serializable属性で列挙型を直列化すると、インスペクタに表示されます。
問題点
値の並び替えや削除はトラブルの原因になる。内部的にはそれぞれの値は整数なので、それが表すものは異なるものになるかもしれない。この例では、Paperの値を削除すると、Scissorsの値は1になる。
あるいは、以下の例のように値を追加した場合。
選択された列挙型の値が、削除されたエントリーの後にあれば、変更される。
これは、特に列挙型に多数の値が含まれる場合、プロジェクトの保守や更新の際に問題を引き起こす可能性があります。空白または未使用の要素を残すか、明示的に整数値を設定することで、この問題を軽減することができます。しかし、どちらの解決策も理想的ではない。
ScriptableObject ベースの列挙型は、従来の列挙型の機能を提供しますが、個々のアセットとして保存されます。例えば、下の例のPaddleBallSOプロジェクトのPlayerIDSO ScriptableObjectを見てください。
基本的に、これは空白のScriptableObjectである。
それを使って、プロジェクト内にP1、P2などのScriptableObjectアセットをいくつも作ることができます。データを含まない場合でも、ScriptableObjectを比較に使うことができる。プロジェクトに新しい ScriptableObject アセットを作成し、名前を付けるだけです。
プロジェクト内で必要なだけプレーヤーIDを作成し、簡単に切り替えることができます。GameDataSOスクリプトで割り当てられたアセットを変更するだけです。
等しいかどうかをチェックする場合は、列挙型と同じように動作する。2つの変数は同じScriptableObjectを参照していますか?もしそうなら、それらは同じアイテムタイプだ。そうでなければ、そうではない。
余分なデータがなくても、ScriptableObjectはカテゴリーやアイテムのタイプを表します。
PaddleBallSOでは、PlayerIDSOがチーム名になる。2つのパドルを区別するために、GameDataSOではP1とP2のアセットを使用しています。
GameSetupスクリプトは、各パドルにプレーヤーIDを割り当てる。ゲームプレイ中、パドルスクリプトはプレーヤーの入力を指定されたチームIDと比較する。
これはあらゆるタイプのマルチプレイヤーゲームに応用できる。あるいは、列挙型に手を伸ばせばどこにでも採用できる。
ScriptableObjectはInspectorの単なる割り当てなので、名前の変更や並び替えの問題はありません。
識別子名をそれぞれ「Player1」または「Player2」に変更したいですか?そうすれば、すべてが機能し続ける。ScriptableObjectを増やす?問題ありません。インスペクタでのアセットの割り当ては変わりません。
この動作は、ゲームプレイを作るのに便利だ。Patterns demoでは、Switch Enumボタンをクリックしてチームを変更する。DemoBallのMonoBehaviourは、それに応じてSpriteRendererを更新します。
ボールがブロックに衝突したとき、ブロックはダメージを受けるのか?平等性の簡単なテストをしてみてください。以下のコード例で、両者を比較する1つの方法を紹介しよう。
このメソッドは、2つのGameObjectが同じチームに属しているかどうかを判定することができる。この単純な比較は、アイテムのピックアップやダメージなど、"チーム "や "アライメント "を持つあらゆるものに適用できる。
楽しいのは、ScriptableObjectにロジックを追加するときだ。従来のenumとは異なり、ScriptableObjectはデータを保持するだけでなく、フィールドやメソッドを持つことができる。
各 ScriptableObject に特化した比較ロジックを持たせるために、これらを使用します。例えば、特殊なダメージ効果(寒冷、熱、電気、魔法など)を定義するScriptableObjectを持つことができる。
ゲームアイテムを装備するためのインベントリシステムが必要なアプリケーションの場合、ScriptableObjectはアイテムタイプや武器スロットを表すことができます。特定のキャラクターは特定のアイテムを持つことができないのですか?魔法のアイテムや特別な能力を持つアイテムもありますか?ScriptableObjectベースの列挙型は、それをチェックするメソッドを追加できる。
前の例のMonoBehaviourDemoBallには、ScriptableObjectを比較するためのAreEqualメソッドが含まれています。ビヘイビアを拡張する場合、比較ロジックを ScriptableObject 自体にバンドルできます。
パターンのデモでは、ボールがオブジェクトに衝突したときに、より選択的になるように修正することができる。以下のコード例で、衝突に関する汎用項目を見てみよう。
これは現在のデモと同じような結果を得ることができるが、現在はm_Weaknessフィールドを持っている。これにより、各ScriptableObjectは、衝突時に破壊する別のScriptableObjectを定義できる。
AreEqualメソッドを呼び出すのではなく、各ScriptableObjectは単純に独自の比較ロジックを管理する。
その結果、より柔軟で拡張性のあるものになった。他チームのブロックをボールが破壊するのではなく、特定することができる。シーン内の複数のボールは、それぞれのCollisionItemによって、異なるブロックを破壊する可能性がある。
これにより、これまでとは違った、より複雑な相互作用の舞台が整う。じゃんけんシステムを作りたかったら、3つのScriptableObjectを定義すればいい:ジャンケンだ。それぞれが独自のm_Weaknessを持ち、IsWinnerメソッドを使って相互作用を処理することができる。
列挙型とは異なり、ScriptableObjectはこのプロセスをモジュール化し、適応可能にする。余分なデータ構造に頼ったり、別個のデータセットと同期するために余分なロジックを追加したりする必要はない。ロジックを処理するために、フィールドやメソッドを追加するだけでよい。
ScriptableObjectベースの列挙型に慣れれば、特にチームメイトと仕事をするときに、ワークフローを改善できることがわかるだろう。これらは資産であるため、更新してもマージの衝突が少なく、データ損失のリスクを減らすことができる。
新しい ScriptableObject ベースの列挙型を追加するのは、別のアセットを作成するのと同じです。従来の列挙型とは異なり、新しい値を追加しても既存のコードが壊れることはない。さらにUnityには、他のアセットと同じように、それらを検索、フィルタリング、整理するツールがすでに組み込まれている。
ボーナスとして、エディターのドラッグ&ドロップUIを使用することで、デザイナーはソフトウェア開発者からの追加サポートなしでゲームプレイデータを拡張することができます。それでも、最初にフィールドを設定する方法を調整する必要はありますが、デザイナーが自分でフィールドにデータを入力することができます。
ScriptableObjectベースの列挙型は、コラボレーションと効率を向上させるためにチームが使用できるリソースの1つです。
ScriptableObjectsのデザインパターンについては、テクニカル電子ブックをご覧ください。 UnityでScriptableObjectsを使用してモジュラーゲームアーキテクチャを作成する.また、一般的なUnity開発のデザインパターンについては、以下をご覧ください。 ゲームプログラミングパターンでコードをレベルアップ.