Unityゲーム設計についての、2つの考え方
はじめに
Unityのゲームアーキテクチャについての対照的な2つの素晴らしい講演について、注釈をつけて解説する。
どちらの講演も、日本語のブログがUnity公式から出ているので、それと講演動画、ソースコードを参照して、私が咀嚼した備忘録的な内容となっている。理解の助けとなれば嬉しい。
1. Scriptable Objectを活用した設計
概要
シングルトンパターンのデメリットから、Scriptable Objectの活用術を4つ紹介している。
Variable
floatなど型を直接クラス内で使う代わりに、このScriptable Objectを使用すれば、エディター上で独立した変数アセットとして扱うことができる。
例えば、同じプレーヤーHPを2つの別のクラスで使う際も、このScriptable Objectをエディター上で生成し、参照をつけてやれば、2つのクラスは互いに疎結合となる。
また、ReferenceというScriptable Objectも紹介されており、これは上記のVariableに変数か、定数かについての表現を追加したものである。
Event
イベントとイベントリスナーで構成され、前者がScriptable Objectとなる。
イベントごとにイベントリスナーが複数個紐づけられ、イベントのRaiseメソッドが呼ばれると、紐づいたイベントリスナー群によって、さまざまなメソッドが発火するというシンプルな仕組みだ。
これもイベントがScriptable Objectであるため、UnityEventに参照を入れ、Raiseを呼び出したりと、エディター上での見通しが良くなるし、それぞれが疎結合となる。
UnityEventはとても使い勝手がいいが、そのまま使うとシーン上のオブジェクトを直接参照に入れなくてはならず、オブジェクト同士が密結合になってしまう。
Set
セットは生成されたゲームオブジェクトをトラッキングすることにもってこいのScriptable Objectだ。
ゲームオブジェクトをセットに設定すると、そのゲームオブジェクト群を一つのScriptable Objectとして扱える。そうすると例えば、ある親ゲームオブジェクトに子ゲームオブジェクト群の参照を持たせるなどの見通しの悪い事態が起こりにくい。
Element
最後に、エレメントだ。これはEnumをより進化させたScriptable Objectと捉えたら良いと思う。
Enumはコード上で変更しなくてはならず、削除や順序を変えるのが難しい。また、追加のデータを加えることはできない。
こうした問題を解決するのが、エレメントである。といっても中身はとてもシンプルで、他のScriptable Objectのリストだ。
例えば、他のゲームオブジェクトと衝突した際に、そのオブジェクトに紐づくエレメントを参照すれば、そのゲームオブジェクトのEnum的な情報を引っ張ってこれる。さらにScriptable Objectなので、順序の変更などはエディタ上で柔軟に可能だ。
まとめ
以上がこの講演の概要だと思う。基本的な方針としてUnityエディターに何が起こっているか把握させ、最大限利用するためのTips集だと理解した。
2. C#クラスを活用した設計
概要
こちらの講演の方が、前述の講演より幅広い内容を扱っている。さらに、後半のTipsについては、上記のブログを読めば十分理解できると思うので、より理解が難しい前半の設計の方に焦点を当てたい。
設計の方針
この講演と、前述の講演の最大の違いはUnityエディターにどれくらい事象を把握させるかだ。
つまり、前述の講演では、Scriptable Objectを最大限活用し、エディター上で様々な作業が完結するようにしている。
一方で、この講演では、Scriptable Objectは使用するものの、あくまでデータを保持するものとし、積極的にエディター外、つまりMonoBehaviourを使用しないC#クラスに処理を分割しようとしている。そのメリットについては後述する。
そのうえで、講演者は「単一責任の原則」に従い、以下の5つにクラスを分割しようと試みている。
Input
名前の通り、入力を扱うクラスである。ロジックやシミュレーションなどからは独立したクラスとなっていることが好ましい。
Simulation
シミュレーションは、この講演では物理計算を行う際に、その計算を置くクラスとして紹介されている。しかし、より汎用的には様々な計算をする際に、その処理を外に出すくらいに考えても良いと思う。
ロジックから使用されるが、シミュレーションはロジックの内容を知らないことが多い。
Logic
ロジックは汎用的ゲームロジックを表す。上記のインプットやシミュレーションを使用し、一つのロジックを構成する。
Presentation
プレゼンテーションはUIを司り、ロジックやシミュレーションを参照し、UIを更新する。
MonoBehaviour
上記の全てをラップして、それぞれのC#クラスのインスタンス生成や、UpdateなどのUnityイベントでの発火を行ったりする。
その他
講演での例では、GameとGameLogicというクラスが、BallなどのMonoBehaviourクラスについての全体的な調整を行っている。
よって、BallなどのMonoBehaviourクラスは、自身についての上記5種類のクラスしか知らず、他のPaddleなどのMonoBehaviourクラスについては知らない構造となっている。
2つの設計の対照性について
上記2つの講演では、MonoBehaviourを多用し、Unityエディターに何が起こっているか把握させるか、MonoBehaviourを使わないC#クラスを使い、積極的にUnity外に実装を出していくかで対象的である。2つの考え方のメリットを確認する。
MonoBehaviourクラス多用のメリット
エディター上で様々な作業を完結させることができる。よって、デザイナーなどに優しい実装が可能だ。さらに実行時の値の変更などシーン上の様々な変更を可視化することができる。
コンポーネント指向の実装もゲームオブジェクトに追加していくだけなので、スクリプト上で行うよりも楽に表現できる。
MonoBehaviourを使わないC#クラス多用のメリット
MonoBehaviourに制限されないため、より幅広いC#の機能や、.Netの機能を使用することが可能だ。さらにUnityへの依存度を下げることで、他のライブラリへの移植も容易になる。
また、スクリプトから実装が追いやすく、プログラマとしては開発しやすい。例えば、どのScriptable Objectがどこの参照に入っているのかをエディター上で追うのはなかなか骨が折れる。さらに、定数か変数かなどもエディター上より表現しやすい。
まとめ
Unityエディターの使用方法が対照的な2つのゲーム設計を見てきた。チームの特性に合わせた設計方針を採用するとメリットを享受できると考える。
採用のお願い
私の所属するカディンチェ株式会社では、積極的にUnityエンジニア、画像処理系エンジニア等の採用を行っております。募集については、コーポレートサイトのリクルートからご確認いただけます。
また、VRメタバースアプリを始めとするVR/ARアプリの開発を行っていますので、お問い合わせはお気軽にどうぞ。