全てのシーンに存在し、一つしか存在してはいけないマネージャー的存在の実装
この記事を読んで、最近読んだFruitsNinjaをCloneしたアセットのことを思い出したので記事にします。
https://www.assetstore.unity3d.com/jp/#!/content/65879
ところで、このアセット、凄いです!画像変えるだけで、vegetable ninjaでもmeat ninjaでも何でも作れます!
こんなん無料で出すなんて太っ腹すぎる!しかもコードに書かれたコメントがめちゃくちゃ丁寧!
オススメです!
本題に戻ります。
上記の記事で問題として挙げられていることを列挙すると
- 全てのシーンに存在して欲しいが、いちいち全てのシーンに配置するのは面倒だし、シーンが変わる度にマネージャーが新しくなるので、シーンを跨いでの処理ができなくなる。
- かといってDontDestroyOnLoadを使ってマネージャーが消えないようにすると、シーンを移動した時にマネージャーが重複してしまう。
- かといって最初のシーンだけに設置すると、他のシーン単体でテストが出来ない。
ということです。なので、
- 全てのシーンに存在し、
- 重複せず
- シーン単体でのテストができる
ことが重要になります。
FruitsNinjaCloneのスクリプトにあるSingletonは、かなり上記の条件を満たしています。
コードを一部簡略化して載せると、
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour { private static T _instance; public static T Instance { get { if (_instance == null) { _instance = (T)FindObjectOfType(typeof(T)); if (_instance == null) { GameObject singleton = new GameObject(); _instance = singleton.AddComponent<T>(); singleton.name = "(singleton) " + typeof(T).ToString(); DontDestroyOnLoad(singleton); } } return _instance; } } }
というような形になっています。
キモは、instanceが無かったらGameObjectを生成して、AddComponentしているところです。
これで、Instanceにアクセスが発生した瞬間にオブジェクトが生成されます。
問題点としては、Instanceへのアクセスが無ければオブジェクトが生成されずEditor上にもオブジェクトが現れないことですが、たいてい、どっかでアクセスがあるし、明示的にInstanceへのアクセスをしてやれば無理やり作ることもできるし、まあまあ良い感じなんじゃないかと思います。