【Unity】シングルトンとは?実装方法とメリット・注意点を初心者向けに解説

Unityでゲームを作っていると、「別のスクリプトにある変数にアクセスしたい」「シーンをまたいでオブジェクトを保持したい」といった場面に出会います。
少数なら GetComponent() や FindObjectOfType() で問題ありませんが、規模が大きくなると管理が煩雑になります。

1個や2個ならまだしも、もっと多くの変数にアクセスしたいとき、毎回オブジェクトを取得するのは面倒ではないでしょうか?

「シングルトン」を使うことで、いちいちオブジェクトを取得せずにアクセスすることができます。

本記事では、シングルトンの実際の使い方について、できるだけ初心者にもわかりやすく解説します。

ゲームを開発するうえで、非常に便利な内容なのでぜひ理解して取り入れてみましょう。

PR

シングルトンとは?

シングルトンとは、クラスから作られるインスタンスを常に1つだけに制限するデザインパターンです。

通常、C#やUnityでは同じクラスから複数のインスタンスを生成できます。しかし、シングルトンを使うことで「世界にひとつだけのインスタンス」を保証し、どこからでもそのオブジェクトにアクセスできるようになります。

Unityでよく使われる場面

  • スコア管理(ScoreManager
  • ゲーム全体の設定を保持する(GameManager
  • サウンド管理(AudioManager
  • シーンをまたいで共有するデータ保持
PR

基本的な使い方

以下のように、ボタンを押したら数字が1つ増える処理を作ってみます。

ScoreManagerという空のオブジェクトを作って、スコアの管理を行います。

2つのスクリプトを用意します。

  • ScoreManager: 数字(スコア)を管理するスクリプト
  • ScoreText: ボタンを押したら数字を増やしてスコアを表示するスクリプト

ScoreTextから、ScoreManagerの変数にアクセスします。

参照元のスクリプト

Awakeの中に、シングルトンの処理を書きます。インスタンスが1つのみ存在するように、複数存在したらDestroyで消すようにします。

using UnityEngine;

public class ScoreManager : MonoBehaviour
{
    public static ScoreManager instance; // インスタンスの定義
    public int number = 0; // この変数にアクセスしたい

    
    private void Awake()
    {
        // シングルトンの呪文
        if (instance == null)
        {
            // 自身をインスタンスとする
            instance = this;
        }
        else
        {
            // インスタンスが複数存在しないように、既に存在していたら自身を消去する
            Destroy(gameObject);
        }
    }
}

補足:シングルトンの呪文について

Awake内を以下のように書くだけでも動作はします。

private void Awake()
    {
        // シングルトンの呪文
        // 自身をインスタンスとする
            instance = this;
    }

ただし、このように書くと、うっかりシングルトンであることを忘れて複数のオブジェクトにこのスクリプトをアタッチしてしまったときに、インスタンスが複数存在することになるので、正確に変数にアクセスできなくなってしまいます。

必ず1つだけ存在するのがシングルトンだよ!

シングルトンであることを忘れなければ良いのですが、忘れて複数生成しても必ず1つになるような処理(最初のコード)にしておくのがベターです。

変数にアクセスするスクリプトの例

今度は先ほど作成したスクリプトの変数にアクセスする例です。

ScoreManager.instance.numberで、ScoreManagerのnumberという変数にアクセスできます。インスタンスは1つしか存在しないので、ScoreManager.instanceだけでアクセスできるという仕組みです。

using UnityEngine;
using TMPro;

public class ScoreText : MonoBehaviour
{
    [SerializeField] TextMeshProUGUI score = default;

    // ボタンを押したら1増やして表示する関数
   public void OnClickButton()
    {
        // ScoreManagerの数字を1つ上げる
        ScoreManager.instance.number++;
        

        // テキスト更新
        score.text = ScoreManager.instance.number.ToString();
    }
}

一行でアクセスできるからいいね!

PR

シングルトンを使うメリット

  1. どこからでもアクセス可能
    ScoreManager.instance のように、簡単に呼び出せる。
  2. インスタンスが常に1つだけ
    複数生成によるデータ不整合を防げる。
  3. シーンをまたいでデータ保持
    DontDestroyOnLoad を使えば、スコアや設定を保持したままシーンを切り替えられる。
PR

シングルトンを使うときの注意点(初心者向け)

シングルトンはとても便利ですが、なんでもかんでもシングルトンにしてしまうと、かえってゲーム作りが大変になることがあります。
ここでは「なぜ注意が必要なのか」を、初心者でもわかりやすく説明します。

1. 依存性が高くなる

シングルトンは「どこからでもアクセスできる変数」です。
これは一見便利ですが、実はグローバル変数をたくさん置いているのと似たような状態になります。

例えば…

  • ゲームのあちこちから「ScoreManager.instance」にアクセス
  • もし ScoreManager を少し変更したら、いろんなスクリプトが動かなくなる

👉 例え話
「家の中心にある1冊のノートに、家族全員がメモを書き込んでいる」状態です。
ノートが破れたり書き方が変わると、みんな困ってしまいます。

2. テストしづらい

シングルトンは1つしか作れないというルールがあります。
そのため、「テスト用に別のインスタンスを用意したい」と思ってもできません。

👉 例え話
「テスト用の練習台を作りたいのに、本番用の1台しかない」状態です。
壊したら困るので自由に試せないんですね。

3. 責務が増えすぎる(なんでも屋になりやすい)

便利だからといって「スコア管理も」「音楽も」「ゲーム進行も」と全部1つのシングルトンにまとめてしまうと、そのクラスがなんでも管理する巨大クラスになってしまいます。

👉 例え話
「町のコンビニに、銀行・病院・郵便局・市役所の機能まで詰め込んでしまう」ようなものです。
最初は便利ですが、あとから直そうとすると大混乱になります。

ポイントまとめ

  • シングルトンはとても便利だけど、万能ではない
  • 「ゲーム全体で唯一の存在でいいもの」に絞るのがコツ
    • ✅ スコア管理
    • ✅ ゲーム進行管理
    • ✅ サウンド管理
  • 逆に「複数あっても問題ないもの」には使わないようにしましょう
PR

中級者向け:シングルトンを多用したいなら

ここまでで、シングルトンが扱えるようになりましたが、シングルトンにしたいスクリプトには、毎回Awake内に「シングルトンの呪文」をコピペしないといけないのが手間ですね。

コピペが不要となる簡単な方法もあるので、その方法を紹介します。

Singletonという名前で新しくスクリプトを作成します。

using UnityEngine;

public class Singleton<T> : MonoBehaviour where T :MonoBehaviour
{
    public static T instance;

    protected virtual void Awake()
    {
        if (instance == null)
            instance = (T)FindObjectOfType(typeof(T));
        else
            Destroy(gameObject);
    }
}

FindObjectOfType(typeof(T)) は、シーン内でT型のコンポーネントがアタッチされている最初のオブジェクトを返します。ただ、返すのはオブジェクト型のため、T型に変換するために頭に(T)をつけています。

このスクリプトを用意しておくと、ScoreManagerが以下のように簡略化できるようになります。

using UnityEngine;

public class ScoreManager : Singleton<ScoreManager>
{
    public int number = 0;
}

すごい簡単に書ける!

以降、他のスクリプトもシングルトンにしたいときは同様にできます。

シーンをまたいでも消去しないようにするには

音量設定など、シーンが切り替わっても消去させたくないものはDontDestroyOnLoad関数を入れましょう。

SingletonDontDestroyという名前のスクリプトを新しく作成します。

using UnityEngine;

public class SingletonDontDestroy<T> : MonoBehaviour where T : MonoBehaviour
{
    public static T instance;

    protected virtual void Awake()
    {
        if (instance == null)
        {
            instance = (T)FindObjectOfType(typeof(T));
            DontDestroyOnLoad(gameObject); // 追加!!
        }   
        else
            Destroy(gameObject);
    }
}

ScoreManagerを対応させるには、以下のようにします。

using UnityEngine;

public class ScoreManager : SingletonDontDestroy<ScoreManager>
{
    public int number = 0;
}
PR

おわりに

シングルトンの使い方と応用の紹介でした。

音量設定やゲームの全体を管理するスクリプトは、シングルトン化しておくことで、開発がしやすくなりますので、活用してみましょう!

データのセーブにおすすめのアセットはこちらです。