「Applibot Advent Calendar 2020」 14日目の記事になります。
前日は@16choさんのBLEで始める心臓の死活監視という記事でした!
はじめに
- UnityのGameObjectの仕様
- デザインや演出の問題
などのため、スッキリしたViewの構造/クラスを作る事はなかなか難しい事だと感じています。
そこで、UnityでアウトゲームなどのViewを組む際、チーム内で定めた規約をご紹介します。
(View構造と書いていますが、広くMonoBehaviour継承クラスが他のgameObjectとの関係性をどう持つか、というテーマになります。)
狙い
ヒエラルキーに配置されたGameObjectは様々な箇所からアクセスする手段があり、global変数のようなものです。
GameObject.Find()などで、どういった構造であっても参照を取得する事が出来てしまいます。
今回ご紹介する規約は、何らかのGameObjectにアクセスできる経路を出来るだけ少なく絞り込む構造とし、メンテナンス性を高める事が狙いです。
説明に使うサンプルについて
public class Qiita : MonoBehaviour
{
// 自分以外のgameObject
[SerializeField] private GameObject _go;
public void PlayXxx()
{
_go.xxx();
}
}
こういったプログラムで自分以外のgameObject(ここでは_go)を管理している、MonoBehaviour継承クラスに関する決め事になります。
ImageやTextのような自身だけを処理する物は含みません。
① inspecterで参照を持ったり、GetComponentで参照を取得できるのは、自身の子供要素に対してのみ
OKな例
- AがA_1の参照を持つ
- A_1がXを参照に持つ
NGな例
- XがB_2の参照を持つ
- B_1がBを参照に持つ
親要素・兄弟要素へのアクセスを禁止し、子供要素へのアクセスのみ許可しています。
これにより依存関係を分かりやすくします。また「再利用のためにprefab化したい」となった時に、子要素以外に参照があるとprefab化するのが困難になるためです。
② 管理しているコンポーネントを飛び越して参照しない
- Aが、A_1 を挟まずにXの参照を取得するのはNG
public class A : MonoBehaviour
{
public void Awake()
{
var x = transform.Find("A_1/X");
}
}
- A_1がXを公開し、A-1.X の用にアクセスするのはNG
public class A_1 : MonoBehaviour
{
[SerializeField] private GameObject _x;
// 自分の子要素を公開
public GameObject X
{
get { return _x; }
}
}
public class A : MonoBehaviour
{
[SerializeField] private A_1 _a_1;
public GameObject Awake()
{
_a_1.X.SetActive(false);
}
}
Xにアクセスできる存在を絞るための規約です。親の管理Componentだけが参照できる事とします。
①・②を踏まえて演出を考慮した構造を作ってみる
最後は規約というより、①と②を守りながら演出を考慮した際の構造を考えてみます。
アニメーション等の演出のため、各Viewパーツをプログラム制御する場面を考えます。
パーツが色々な箇所に散らばっていると制御が困難になるため、共通の親を用意します。
例えばA_1とA_2が同時に動いたり、相互に影響しあうアニメーション演出が考えられる際、A_1とA_2の参照を持つ親のAnimationRootを作り、子要素達の動きを制御します。
更にAnimationRootAとAnimationRootBが関連するアニメーションを作るには、AとBの参照を持つ親Rootコンポーネントを用意し、子要素のComponentへ指令を出してタイミング等を制御します。
最後に
規約により、分かりやすさ・メンテナンス性は上がりますが、記述は冗長になり面倒が増える側面もあります。
より良い構造設計があれば是非教えて下さい!
また、皆さんのチームのView設計規約があれば、合わせて紹介いただけると幸いです。
「Applibot Advent Calendar 2020」 14日目の記事でした。
明日は @lokiunybg さんです。