【C++】シングルトンパターンとは?|ゲームのマネージャクラスで解説

サムネイル画像 C++

今回は、C++でよく出てくる「シングルトンパターンとは何か」について解説していきます。

「シングルトンって何?」
「ゲームでマネージャクラスに使うってどういうこと?」
「普通のclassと何が違うの?」
こんな疑問はありませんか?

シングルトンパターンは、インスタンスを1つだけに制限したいときに使う設計です。ゲーム制作では、設定管理やシーン管理、入力管理などのマネージャクラスで見かけることがあります。この記事では、初心者向けに意味・必要性・C++での実装方法を、ゲームのマネージャクラスを例に解説していきます。

シングルトンパターンとは?

シングルトンパターンとは、あるclassのオブジェクトを1つしか作れないようにするデザインパターンです。

たとえば、ゲーム全体の状態を管理するGameManagerが何個も作れてしまうと、「どの設定が本物なのか」「今のシーンはどれなのか」が分かりにくくなります。そこで、最初から1つだけ使う前提にして管理しやすくする、という考え方です。

デザインパターン全体の考え方を先に整理したい方は、ゲーム開発で使うデザインパターンの記事も参考になります。

なぜシングルトンが必要?

ゲームでは、「どこからでも同じ管理情報を使いたい」場面があります。たとえば、音量設定、現在のシーン番号、スコア管理、入力状態などです。

こういった情報を毎回いろいろなclassに渡していく設計もできますが、最初のうちは少し複雑に感じやすいです。そこで、1つだけ存在するマネージャクラスとしてまとめると、構造を理解しやすくなります。

もちろん、何でもシングルトンにすればいいわけではありません。ただ、初心者がゲーム全体の流れを整理する段階では、かなり分かりやすい考え方です。

シングルトンの基本的な実装方法

シングルトンでは、主に次のような形を使います。

  • コンストラクタをprivateにする
  • 自分自身のインスタンスをstaticで持つ
  • 外からは専用の関数で取得する

classやコンストラクタの基本がまだあいまいな方は、classの記事コンストラクタとデストラクタの記事を先に見ておくと理解しやすいです。

ゲームのマネージャクラスでの実装例

今回は、シーン番号を管理するGameManagerを例にしてみます。

▼main.cpp

#include <iostream>
#include <string>

class GameManager {
private:
    int currentScene;

    GameManager() : currentScene(0) {
    }

public:
    static GameManager& GetInstance() {
        static GameManager instance;
        return instance;
    }

    void SetScene(int scene) {
        currentScene = scene;
    }

    int GetScene() const {
        return currentScene;
    }

    void ShowScene() const {
        std::cout << "Current Scene: " << currentScene << '\n';
    }
};

int main() {
    GameManager& manager1 = GameManager::GetInstance();
    GameManager& manager2 = GameManager::GetInstance();

    manager1.ShowScene();
    manager1.SetScene(2);
    manager2.ShowScene();

    if (&manager1 == &manager2) {
        std::cout << "同じインスタンスです\n";
    }

    return 0;
}

このコードでは、GameManagerのコンストラクタをprivateにしているので、外から自由に生成できません。代わりにGetInstanceを通して、常に同じ1つのインスタンスを使います。

実行結果

Current Scene: 0
Current Scene: 2
同じインスタンスです

manager1で変更したシーン番号がmanager2から見ても同じになっているので、1つの共有インスタンスを使っていることが分かります。

マネージャクラスで使うと何がわかりやすい?

ゲーム制作では、SceneManager、AudioManager、InputManagerのように、全体で1つだけあれば十分な役割のclassが出てきます。こうしたclassにシングルトンを使うと、どこからでも同じ管理対象を触れるので、最初の設計としてはかなり理解しやすいです。

ただし、便利だからといって増やしすぎると、逆に依存関係が見えにくくなります。「本当に1つであるべきか」は意識しておくのがおすすめです。

【重要】私が実際にシングルトンで困った体験談

私が個人でゲームを作っていたとき、最初は「マネージャっぽいものは全部シングルトンにしておけば便利そう」と思って、InputManager、AudioManager、EnemyManager、EffectManagerなどをどんどんシングルトン化したことがありました。

最初は確かに呼び出しやすかったのですが、あとから修正するときに「どこから値が変わったのか」が見えにくくなって困りました。特に、複数の場所から同じマネージャを触れるので、予想外のタイミングで状態が変わっていたんです。

そこで、本当に全体で1つだけ必要なものだけをシングルトンにするように整理したところ、かなり管理しやすくなりました。個人開発では便利さに引っ張られやすいですが、増やしすぎには注意したほうがいいです。

シングルトン使用時のよくある失敗例と対処法

1. コンストラクタをpublicのままにしてしまう

これだと外から何個でも作れてしまい、シングルトンになりません。constructorはprivateにするのが基本です。

2. 何でもシングルトンにする

便利ですが、使いすぎると設計が見えにくくなります。全体で1つしかいらない管理対象だけに絞るのがおすすめです。

3. 状態の変更箇所が追えなくなる

どこからでもアクセスできるぶん、値の変化を追いにくくなります。挙動が分かりにくいときは、Visual Studioのデバッグ方法の記事もかなり役立ちます。

注意点

シングルトンは、初心者にとって「1つだけの管理役」を作るのに分かりやすいパターンです。ただし、設計が大きくなるほど、依存が強くなりやすいという弱点もあります。

なので、まずは設定管理やシーン管理のように、役割がはっきりしているマネージャクラスで使ってみるのがおすすめです。逆に、キャラや弾のように複数必要なものには向きません。

まとめ

  • シングルトンパターンは、インスタンスを1つだけに制限する設計
  • ゲームではGameManagerやSceneManagerのようなマネージャクラスで使われやすい
  • 実装の基本は、privateコンストラクタ・staticインスタンス・取得関数
  • 便利だが、何でもシングルトンにすると逆に管理しにくくなる
  • 本当に1つだけ必要な役割に絞って使うのが大事

関連記事