【Unity】呼び出しと管理が簡単、シングルトン設計のオブジェクトを作る
そもそも、シングルトン設計って?
シングルトン設計の基本的な定義としては、シーンの中でその役割を持つオブジェクトが一つしか存在しないこと。デザインパターンの中で定義されていて、Unityを用いたゲーム開発以外でも用いられます。
……と言っても、パッと見ではイメージが難しいです。
すげー簡単に言えば、
「俺以外はいらねぇ!俺と同じやつは俺以外みんな消す!」
という、バーサーカー思想のオブジェクトのことです。
(異論は認める)
シングルトン設計のメリット
そんなバーサーカーことシングルトン設計のメリットですが、私個人の思う大きなメリットは2つ挙げられます。
1. オブジェクトの管理が楽になる
上記に挙げたように、シングルトン設計を用いたオブジェクトは結果的にシーンの中で1つしか存在しません。そのため、うっかり2つ以上配置してしまった場合や、何かの拍子にもう一つ生成されてしまった場合でも2個目以上を打ち消して、1つしか残らない状況を作り出してくれます。そのため、オブジェクトを統括するマネージャーなどを作る際に役立ちます。
シーンを跨いでBGMを流したい場面も存在するためDontDestroyOnLoadを用いたサウンド管理、しかしシーンを跨いだときに切り替え先のサウンド管理と役割が被ってしまうことがあります。そんなときにシングルトン設計。勝手に重複するオブジェクトを削除してくれるので、役割が被って誤作動を起こすことを避けてくれます。やったね!
2. オブジェクトの呼び出しが楽になる
シングルトン設計を用いたオブジェクトはシーン内に一つしか存在しません。そのため、オブジェクトがどこにあるのか探して、GetComponentでComponentを取得して、という手順を踏む必要はありません。
ここで大きな役割を果たすのがstaticでpublicなプロパティ。突然言われると「え?なんて?」ですが、詳しく書くと別記事を書けるレベルのボリュームなので簡単に説明します。staticはスクリプト(クラス)がアタッチされたオブジェクトではなく、クラスに情報を持つとでも思ってください。C言語やC++を学んでいる方は、グローバル変数を思い浮かべると分かりやすいです。publicはどこからでもアクセスできるアクセス指定子です。プロパティは変数のように取り扱える関数。値を渡したり値を変えることが主な役割ですが、関数のようにその中で処理を書くことができます。
そして、そのstaticでpublicなプロパティに継承先の情報を持たせることで、クラス名を指定するだけで簡単に呼び出すことができます。
ソースコード
gista6da23ed712649354b0bba8b963e049f
使い方
SingletonMonoBehaviourを継承する
このシングルトン設計のクラスは継承を前提として使います。
Unityで新しいクラスを作ると自動的に継承されるMonoBehaviourを継承しているため、このSingletonMonoBehaviourを継承したクラスでも、MonoBehaviourが備えている基本的なメソッドや変数を取り扱えることができます。
(さて、ここまでで継承という言葉は何度出てきたでしょうか…)
シングルトン設計を使いたいクラスの継承元をSingletonMonoBehaviour<継承元のクラス名>とすることで、シングルトン設計を自動的に受け継ぐことができます。具体的な書き方は、以下の画像を参照してください。
呼び出し方
呼び出し方は、継承先のクラス名.Instance.メソッド(もしくは変数)のような形式で呼び出します。この内、Instanceとはstaticでpublicなプロパティです。SingletonMonoBehaviourのソースコードを編集すれば、Instanceではなく独自の名前に設定することができます。具体的な書き方は、以下の画像を参照してください。
シーン遷移時に破棄オプション
このSingletonMonoBehaviourにはdontDestroyOnLoadという関数が用意されていますが、このbool型変数の値を継承先で変更することでシーン遷移時に破棄を設定することもできます。
具体的にどういうシチュエーションで使用するのかと言えば、例えばシーンごとに値を変更したいが、シングルトン設計のメリットは失いたくないとき等に使います。シーン遷移時に破棄する設定にすることで、シーンごとに設定された値を反映することなどの細かい設定が可能になります。
また、初期設定では破棄しない設定になっているため、このオプションを使いたくない場合はわざわざ継承先で値を変更する必要はありません。
dontDestroyOnLoadの値を変更する際は、継承先のAwake関数で値を変更してください。Start関数だと処理が終わった後に呼び出されることになるので、お気をつけください。
具体的な使い方は以下の画像で紹介しますが、設定の際は注意が必要なため、以下の注意書きもお読みください。
Awakeを継承先で使用するときの注意書き
シングルトン設計を用いたSingletonMonoBehaviourでは、初期設定の際にAwake関数を使用しています。「Awake関数とはなんぞや?」という話ですが、Unityで初期設定されている関数の一つで、基本的にはStart関数と役割は同じであるもののStartよりも先に呼ばれるというものです。
継承先でAwakeを使用することもあるかと思いますが、その際はoverrideを書いた上でbase.Awake()で継承元を呼び出してください。
overrideとbaseを軽く説明すると、overrideは継承元に同じ名前の関数が合った場合、上書きするというものです。baseは継承元の関数や変数を呼び出す際に使います。baseは通常の場合は省くことができるのですが、今回は関数名が被っているため必要となります。
なお、以上の注意書きは継承先でAwakeを使わない場合は関係ありません。
その場合は特に気にせず、スクリプトをお書きください。
スクリプトの説明
以下の説明は詳しい処理に興味がある方のみ、お読みください。
シーン内の同一オブジェクトを検索して削除する
先の説明でシングルトン設計は同一オブジェクトが複数存在する場合は削除すると言いましたが、その処理を行っているのがこちらです。
序盤では俺以外全員消すバーサーカーと紹介しましたが、この処理、よく見るととあることに気が付きませんか…?
実はDestroyで削除しているのは自身のオブジェクト。つまり、自身と同じオブジェクトが存在した場合は自分を消しているということです。なんと、シングルトン設計はバーサーカーではなく自爆野郎だったということなんですね。
オブジェクトが存在しない場合は警告を出す
上記の解説でバーサーカーではない事が判明したシングルトン設計ですが、実は自分が存在しないと怒るかまってちゃんでもあります。
シングルトン設計を用いたオブジェクトは重要なことが多いので、シーンにクラスがアタッチされたオブジェクトが存在しない場合はエラーを出す処理を書いています。また、初回起動時はスクリプトがアタッチされているオブジェクトを検索して、その情報を変数に格納するのもここの処理で行っています。これらは初回起動時しか行われない(=変数に情報が存在するときは行わない)ので、省エネ設計でもあります。
また、エラーを出す設定を消す場合は // 見つからなかった場合 というコメントが付いてるif文を削除してください。これで、オブジェクトが存在しない場合でもエラーを出さないようになります。
最後に
長い記事でしたが、最後までお読み頂きありがとうございました。