Zenjectが流行ってるけど、UnityのInspectorをDIコンテナに見立てて、デコレータパターンを実装する考察
作るもの
キャラクターの周りを旋回する三人称カメラを作成する。
通常はマウスの動きに合わせてカメラが動く。しかし、イベントリを表示するなどGUIを操作する際は動かしたくないので、それに備えてカメラが動く条件を装飾できるようにする。
準備
こんな感じでシーンを用意。
準備の説明は面倒なので、Githubで配布してます。
コンポーネントの作成
デコレータパターンを実装するための、4つのコンポーネントを作ります。
CameraRotationBase
継承させて使う雛形のコンポーネント。
Rotationメソッドでゲームオブジェクトを回転させますが、値が0なので動かないです。
using UnityEngine;
public class CameraRotationBase : MonoBehaviour {
virtual public float XValue { get { return 0; } }
virtual public float YValue { get { return 0; } }
public virtual void Rotation()
{
transform.localEulerAngles += new Vector3(YValue, XValue, 0);
}
}
CameraRotationMouse
さきほどのコンポーネントを継承します。
値をマウスの動きでオーバーライドします。
using UnityEngine;
public class CameraRotationMouse : CameraRotationBase
{
override public float XValue { get { return Input.GetAxis("Mouse X"); } }
override public float YValue { get { return Input.GetAxis("Mouse Y"); } }
}
CameraRotationClickDecorator
デコレータ用コンポーネント。
Rotationメソッドを右クリックを押していないと、呼ばれないようにデコレーションします。
using UnityEngine;
public class CameraRotationClickDecorator : CameraRotationBase
{
public CameraRotationBase decorator;
public int buttonIndex = 1;
public override void Rotation()
{
if (Input.GetMouseButton(buttonIndex))
{
decorator.Rotation();
}
}
}
CameraControl
RotationメソッドをUpdateメソッドで呼び出すコンポーネントです。
cameraRotationはCameraRotationMouseかCameraRotationClickDecoratorを登録できます。
using UnityEngine;
public class CameraControl : MonoBehaviour
{
public CameraRotationBase cameraRotation;
void Update()
{
cameraRotation.Rotation();
}
}
完成
CameraControlのcameraRotationに登録するコンポーネントによって挙動が変わります。
CameraRotationMouseを登録した場合は常にマウスの動きに合わせてカメラが動くようになります。
CameraRotationClickDecoratorを登録した場合は右クリックを押していないとカメラが動きません。
比較のデモを記事上で披露できれば良いですが、ちょっと難しい。
完成版プロジェクトはこちら
まとめ
デコレータパターンで既にある機能に何かを加える例を紹介しました。
自分が書いたコードを誰かに改編される際に、
デコレータパターンで変更可能なコードにしておけば、既にあるコードを崩されずに処理を変えられます。
本来のデコレータパターンはinterfaceとか使って作るんだけど
inspectorの仕組み考慮したら、Unityではこんな感じで作ると良いかもしれない。