【Unity】シングルトンとは?クラスのインスタンスが必ず一つしか存在しない

シングルトンとは? Unity

こんにちは、ともくんのゲーム作り部屋にようこそ!

このページでは、

「Unityでゲームを作る際に使うシングルトンってなに?」

「シングルトンを使うとどういうメリットがあるの?」

というお悩みの方に向けた内容となっています。

Unityでゲームを作る際に、シングルトンという手法が使われることがあります。

シングルトンとは、クラスのインスタンスが必ず一つしか生成されないようにすることで、Unityの機能という訳ではなく、プログラミングにおける記述方法になっています。

このシングルトンを使うことで、他のスクリプトから変数を取得しやすくなるといったメリットがあります。

そこで、このページでは、Unityのゲーム作りで便利なシングルトンについて、どんな仕組みや特徴があるのか、またシングルトンの書き方や実際の使い方についてまとめていきます。

この記事を書いた人

ゲーム作りを学び始めた一児のパパです。
このブログは、子供から「ゲームを作ってみたい!」と言われ、非プログラマーでゲーム作りをしたことない僕が、ゲーム作りの本を読んで独学でゲーム開発を学んでいるブログです。
同じように初めてゲーム作りをしている方と一緒に学んでいけるようなブログに出来たらいいなと思っています。
また、「このコードはおかしい」とか「もっと良い書き方があるよ!」などあれば、どんどん指摘して頂けると助かります。

シングルトンとは?クラスのインスタンスを一つだけにする記述方法

シングルトンは、そのクラスにおけるインスタンスを一つだけにしてあげるように、スクリプトを書いていく手法になります。

通常、クラスというのは設計図のような役割を持っていて、その設計図を元にして複数のインスタンスを生成することができます。

そして、それぞれのインスタンス毎にクラスで定義した変数やメソッドを持つことになります。

一方で、シングルトンは、複数のインスタンスが生成されないように、必ず一つだけのインスタンスになるように設計されたものになります。

複数のインスタンスが生成されないので、クラス内で定義した変数やメソッドは、そのインスタンスしか保持していないものになります。

例えば、ゲームのスコアやプレイヤーのライフなど、ゲーム内で一つしか存在しない変数を保持させるインスタンス(GameManagerなど)を作るのに、シングルトンが非常に便利に使えます。

シングルトンの書き方

シングルトンの基本的な書き方は、

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance; // GameManager型の変数instanceを宣言

    void Awake()
    {
        if (instance == null)   // instanceに中身が入っていない場合
        {
            instance = this;    // このインスタンス自身を入れる
        }
        else                    // instanceに中身が入っている場合
        {
            Destroy(this.gameObject);   // インスタンスに紐づくオブジェクトを破壊
        }
    }
}

上のように書いてあげることで、インスタンスが一つだけ生成される仕組みを作ることができます。

このスクリプトをもう少し詳しく解説していきます。

空オブジェクトを作りスクリプトをアタッチする

まずは、Unity内に空のオブジェクトを作成しておきます。

そして、この空オブジェクトに対して、スクリプトをアタッチしておきましょう。

ここでは、「GameManager」というスクリプト名で作成しています。

インスタンスを入れるクラス型の変数を作る

このスクリプト内で、インスタンスを入れるクラス型の変数「instance」を宣言しています。

public static GameManager instance;	// GameManager型の変数instanceを宣言

この変数は「public static」を付けて宣言します。

staticは、

  • 常に存在しているもの
  • 一つしか存在しないもの

を作るために使われる修飾子になっていて、これによりinstanceという変数は一つしか存在しないものになります。

また、public staticにしておくことで、

GameManager.instance

のように「クラス名.クラス型の変数」と書くことで、外部から簡単にアクセスすることができるようになります。

Awake内でシングルトンの処理を書く

ここから、Awakeメソッド内でシングルトンの処理を書いていきます。

Awakeメソッドは、Startメソッドよりも前に呼ばれるイベント関数で、インスタンスの生成直後に呼ばれるメソッドです。

先ほどの「instance」には、まだ中身が入っていないので、このAwakeメソッドの中で他の処理よりも先に中身を入れてあげる必要があります。

    void Awake()
    {
        if (instance == null)   // instanceに中身が入っていない場合
        {
            instance = this;    // このインスタンス自身を入れる
        }
        else                    // instanceに中身が入っている場合
        {
            Destroy(this.gameObject);   // インスタンスに紐づくオブジェクトを破壊
        }
    }

11行目で、「instance = this;」と書くことで、中身を入れる処理を書いています。

この「this」は、そのインスタンス自身を表していて、これを変数instanceの中身として入れる処理をしています。

ただし、中身がすでに入っている場合と入っていない場合で処理を変える必要があるため、9行目でif文を使って中身が入っていないのをnullでチェックして制御しています。

もしすでに中身が入っている場合は、インスタンスが複数存在しないように削除しておく必要があるので、「Destroy(this.gameObject)」でそのインスタンスに紐づくゲームオブジェクトを破壊しています。

これによって、GameManagerはゲーム内に一つしか存在しないものにすることができました。

シングルトンの使い方

ここからは、シングルトンを使って、

の方法をそれぞれ紹介していきます。

別のスクリプトから変数を取得する

シングルトンを使って書いていくことで、別のスクリプトから変数を取得するのが非常に簡単になります。

例えば、先ほどのシングルトンで作ったGameManagerの中に、6行目で変数scoreを宣言しておきます。

using UnityEngine;

public class GameManager : MonoBehaviour
{
    public static GameManager instance;
    public int score;

    void Awake()
    {
        if (instance == null)
        {
            instance = this;
        }
        else
        {
            Destroy(this.gameObject);
        }
    }
}

そして、別のスクリプトからこの変数scoreにアクセスして10を加算してあげるといった場合、

using UnityEngine;

public class Test : MonoBehaviour
{
    void Start()
    {
        GameManager.instance.score += 10;
    }
}

と、7行目のように「GameManager.instance.score」と書いてあげることで、簡単に変数にアクセスして加算したり減算したりできるようになります。

シーン間でデータ共有できるようにする

このGameManagerのオブジェクトに対して、DontDestroyOnLoadメソッドを使うことで、シーン遷移してもGameManagerで管理しているデータを削除させないようにすることができます。

DontDestroyOnLoadメソッドは、別のシーンが読み込まれてもそのオブジェクトを破壊せず、次のシーンにも残すようにする処理を行うメソッドです。

これをGameManagerに対して行うことで、シーンが切り替わっても常にGamaManagerが残り、変数のデータも保持されるという状態を作ることができます。

using UnityEngine;

public class GameManager : MonoBehaviour
{
	public static GameManager instance;
	
	void Awake()
	{
		if (instance == null)
        {
			instance = this;
			DontDestroyOnLoad(this.gameObject);	// シーンが切り替わってもオブジェクトを残す
		}
		else
		{
			Destroy(this.gameObject);
		}
	}
}

そのため、メインシーンで加算したスコアの値を別のリトライシーンやリザルトシーンなどで表示したいといった時に、このシングルトンで生成したインスタンスにスコア変数を定義した上で、DontDestroyOnLoadメソッドを使うことで実現できます。

まとめ

このページでは、Unityでスクリプトを書く際に使うことができるシングルトンについて、仕組みや特徴、また書き方から使い方までを紹介していきましたが、いかがでしたでしょうか?

シングルトンとは、そのクラスにおけるインスタンスを複数存在しないようにするスクリプトの記述方法です。

シングルトンの形で書いてあげることで、

といったメリットがあります。

ゲーム内で変数を管理するGameManagerなどで、シングルトンは良く使われることが多いです。

最後までお読みいただきまして、ありがとうございました!

コメント