こちらの記事を参考にしたSingletonMonoBehaviourを利用していたのですが、SingletonMonoBehaviourの絡むバグが発生し、それを発生しにくくできないかと思って、ちょこっと変えてみました。
上記のSingletonMonoBehaviourでは、Instanceにアクセスすると最初の一度だけ、 FindObjectOfType( typeof( T ) ); をしています。
この時に、そのオブジェクトのactiveがfalseだと見つからなくてエラーになるという問題がありました。
まあ、普通はactivateをfalseになんてしていないと思うんですが、例えば、
class HogeManager : SingletonMonoBehaviour<HogeManager>
というのがあったときに、
class HogeMain{ public HogeManager hogeManager;//Inspectorで与えとく void Start() { hogeManager.SetActive( false );//最初は使わないから false にしとこう。 ... //いろいろ処理 HogeManager.Instance.Function();//HogeManagerのFunctionを呼ぼう! <- ここで死亡 } }
という感じで死んでしまったことがありました。
それでも、普通はAwakeが呼ばれたさいにinstanceに値が入るのでだいじょうぶなんですけど、往々にして継承先でAwakeを書きたくなるんで、継承元のAwakeを隠しちゃっていました。
隠しちゃってるよっていう、warning出ていたんですけどね。
継承先でAwakeを書きたくなることは結構あるので、継承元のAwakeをvirtualにしました。
そして、継承先で、
protected override void Awake() { base.Awake(); ...//継承先独自の処理 }
としています。
ただ、これでもAwake内でSetActive(false)されて、Instanceにアクセスされたり、そもそもEditor上でactiveをfalseにされていたら、同様にエラーになっちゃいますけど。
他にも、
abstractにしてたり、 where T : SingletonMonoBehaviour
では、ソース。
using UnityEngine; public abstract class SingletonMonoBehaviour<T> : MonoBehaviour where T : SingletonMonoBehaviour<T> { private static T instance; public static T Instance { get { if ( instance == null ) { instance = ( T )FindObjectOfType( typeof( T ) ); if ( instance == null ) { Debug.LogError ( typeof( T ) + "is nothing" ); } } return instance; } } protected virtual void Awake() { CheckInstance(); } protected bool CheckInstance() { if( instance == null) { instance = (T)this; return true; }else if( Instance == this ) { return true; } Destroy(this); return false; } void OnDestroy () { instance = null; } }