原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】公式サンプルプロジェクトで学ぶデザインパターン:Singleton

空気清浄機

新しく購入した空気清浄機の前でおならをしたらランプが真っ赤になって軽くショックを受けた皆さんこんにちは。自分の放屁がランプを真っ赤にするほど空気を汚すとは知りませんでした。以後気を付けます。

 

ソニックフロンティア

当初は購入予定ではなかったのですがネットの評判が良かったので購入しました。


従来のステージクリア型のソニックからオープンワールドに変わった本作ですが、私のような濃いソニックファンではないカジュアルなユーザには非常に楽しい内容になっていると思います。

これまでオープンワールドゲームと言えば自由なシナリオ進行と探索の深さを楽しむ物が主流となっていましたが、『Marvel's Spider-Man』の発売を契機として最近ではフィールド間の移動を楽しむ事に重点を置いたゲームがオープンワールドの一つの支流として確立されつつあり、『ソニックフロンティア』はこの支流に沿ったゲームであるといえます。

フィールド内に点在するチェックポイントのギミックを解除⇒従来型ソニックのステージをクリア、というゲームフローですが、ソニックらしい高速走行とレールライド、ピンボールジャンプ等のギミックによる空間移動は爽快感がありそれだけで楽しいため、ストーリーを追わずにただフィールドを彷徨うだけでも時間を忘れて遊ぶことが出来ます。

妙にフォトリアルよりなグラフィックで敵のデザイン(特にカラーリング)が地味だという事と、やけに中二病っぽい台詞回しは気になるところですが、それを上回るぐらいソニックの操作が楽しく爽快感が得られるゲームだと思います。

デザインパターン講座4回目

Unity公式から公開されているデザインパターン学習用のサンプルプロジェクト

github.com

各デザインパターンがディレクトリ別に格納されています。

 

今回はそのサンプルプロジェクトに関する解説4回目、「8 Singleton」になります。
前回まで解説は以下

www.karvan1230.com

www.karvan1230.com

www.karvan1230.com

 

Singletonパターン

このパターンを簡単に説明すると、生成するインスタンスの数を1つに制限した設計パターンと言えます。

RPGなどのゲームを例にとると、プレイヤーのキャラクターやNPC、敵といったキャラクターはゲーム内で多数存在するため、その分それを制御するクラスは複数必要ですが、ゲーム全体の運行を管理する神視点のクラスは複数存在するとかえって処理が煩雑になり、後々のバグの原因となのでゲーム内に一つだけ存在する方が望ましいです。
この「ゲーム内に1つしか存在」を実現し、かつ保証する組みがSingletonパターンとなります。

 

サンプルシーン

「8 Singleton」配下には以下のようなファイルが格納されています。

 

そして、ここに格納されているサンプルシーン「Singleton」を実行してみるとこんな動作をします。

ゲーム実行前は複数あったスピーカーのオブジェクトが一つになり、クリックによりそのスピーカーから音が鳴ります
(動画では音がないため、スピーカーを揺らす処理を行っています)

各スピーカーにはそれぞれSingletonを継承したAudioManagerクラスがアタッチされており、起動時に各自インスタンスを生成しようとしますが、既に自身以外のSingletonインスタンスが存在する場合は生成を行わず、逆に自身を削除(Destory)しています。
これによりゲーム開始から最も先にインスタンスを生成したスピーカーのみが残り、「ゲーム内に1つしか存在」が見た目は実現します。

private void RemoveDuplicates()
{
    if (_instance == null)
    {
        _instance = this as T;
        DontDestroyOnLoad(gameObject);
    }
    else
    {
        Destroy(gameObject);
    }
}

 

唯一の存在を保証する

上記の処理によりゲーム開始時に「ゲーム内に1つしか存在」が見た目は実現できましたがこれだけでは不十分で、外部からの新規作成・コピーの禁止を保証して、ゲーム開始以後も「唯一の存在」が壊れない仕組みを実現する必要があります。
この為、Singleton(ゲーム内に1つ)となるクラスは以下のルールに準拠して製造する必要があります。

  1. 自身の型のインスタンスが privateなクラス変数として定義されている
  2. 外部から生成されないようにprivateにしている
  3. インスタンスを返すためのクラス関数が定義されている

 

サンプルシーンのSingletonクラスではこれらのルールが以下の形で実装されています。

1.自身の型のインスタンスが privateなクラス変数として定義されている

private static T _instance;

 

2.外部から生成されないようにprivateにしている

private static void SetupInstance()
{
    // lazy instantiation
    _instance = (T)FindObjectOfType(typeof(T));

    if (_instance == null)
    {
        GameObject gameObj = new GameObject();
        gameObj.name = typeof(T).Name;

        _instance = gameObj.AddComponent<T>();
        DontDestroyOnLoad(gameObj);
    }
}

 

3.インスタンスを返すためのクラス関数が定義されている

public static T Instance
{
	get{return _instance;}
}

 

上記の対応によりSingletonのクラスは自分自身のインスタンスをグローバルなstaticメンバとして持ちます。
この為、他クラスからSingletonのクラスの関数を呼び出す場合は、

クラス名.Instance.関数

の形で呼び出すことができるのでかなり便利になります。

 

MonoBehaviourを継承しよう

UnityでSingletonパターンを採用したクラスを作成する場合はMonoBehaviourを継承したクラスをSingleton化する方が色々便利です。
この為、サンプルシーンでは以下のような形でMonoBehaviourを利用しています。

 

・MonoBehaviourを継承したクラスをSingletonクラス

public class Singleton<T> : MonoBehaviour where T : Component
{
	private static T _instance;
	public static T Instance
	{
		if (_instance == null)
		{
			_instance = (T)FindObjectOfType(typeof(T));

			if (_instance == null)
			{
				SetupInstance();
			}
			else
			{
		        string typeName = typeof(T).Name;
			}
		}

		return _instance;
	}
}

 

・Singletonを継承したGameManagerクラス

public class GameManager : Singleton<GameManager>
{
}

 

まとめ

Singletonパターンとは生成するインスタンスの数を1つに制限した設計パターンです。
Singletonクラスは外部からの生成・コピーを禁止し、自分自身のインスタンスをグローバルなstaticメンバとして持ちます。
Untiyで利用する場合はMonoBehaviourを継承したクラスをSingleton化しましょう。

 

 

◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。