概要
Unityでゲームを開発していると、シーンを切り替えた際に「このオブジェクトだけは消えてほしくない」という状況に必ず直面します。例えば、ゲーム全体を通して流れ続けるBGMを再生するAudioSourceを持ったオブジェクトや、プレイヤーのスコアや設定などの状態を管理するゲームマネージャーなどがこれに該当します。
Unityの標準的な動作では、SceneManager.LoadScene()などで新しいシーンをロードすると、古いシーンに存在していたすべてのGameObject(ゲームオブジェクト)は自動的に破棄されてしまいます。その結果、シーンを切り替えるたびにBGMが途切れたり、ゲームの状態がリセットされてしまうという問題が発生します。
この問題を解決し、特定のオブジェクトをシーンの切り替えから守るために用意されているのが、UnityのObject.DontDestroyOnLoad()メソッドです。この記事では、基本的な使い方から、シングルトンパターンとの組み合わせ方までを解説します。
DontDestroyOnLoadの基本概念
DontDestroyOnLoadは、Objectクラスの静的メソッドです。このメソッドにGameObjectを渡すと、そのオブジェクトは「DontDestroyOnLoadシーン」と呼ばれる特殊な内部シーンに移動し、以降のシーン切り替えの影響を受けなくなります。
DontDestroyOnLoadシーンは、通常のシーンとは異なり、ゲームが終了するまで破棄されません。これにより、BGMやゲームマネージャーといった、ゲーム全体で永続的に存在する必要があるオブジェクトを簡単に管理できるようになります。
コード例1:基本的な使い方
最もシンプルな使い方は、永続化したいオブジェクトにアタッチされたスクリプトのAwake()メソッド内でDontDestroyOnLoad(this.gameObject)を呼び出すことです。
以下の例は、BGMを再生するオブジェクトにアタッチすることを想定したスクリプトです。
using UnityEngine;
public class BgmPlayer : MonoBehaviour
{
void Awake()
{
// このGameObjectをシーン切り替え時に破棄されないように設定します
DontDestroyOnLoad(this.gameObject);
// BGMの再生を開始する処理などをここに追加します
Debug.Log("BGMプレイヤーが生成され、DontDestroyOnLoadが適用されました。");
}
}
このスクリプトをアタッチしたGameObjectがシーンに配置されていれば、シーンを何度切り替えても、そのGameObjectは破棄されずに残り続けます。
初心者が躓きやすいポイント:オブジェクトの重複生成
DontDestroyOnLoadを使う際に、初心者が最も陥りやすい間違いは「オ ブジェクトの重複生成」です。
例えば、上記のBgmPlayerがシーンAに配置されており、シーンBにも同じBgmPlayerが配置されているとします。シーンAからシーンBへ移動すると、以下のようになります。
- シーンAの
BgmPlayerにDontDestroyOnLoadが適用され、永続化されます。 - シーンBがロードされると、シーンBに配置されていた新しい
BgmPlayerが生成されます。 - 結果として、ゲーム内に
BgmPlayerが2つ存在し、BGMが二重に再生されてしまう、といった問題が発生します。
コード例2:シングルトンパターンを用いた安全な管理
この重複生成の問題を解決し、永続化したいオブジェクトがゲーム内にただ一つだけ存在することを保証するために、DontDestroyOnLoadはシングルトンパターンと組み合わせて使用されるのが一般的です。
シングルトンパターンとは、「クラスのインスタンスが一つしか存在しないことを保証する」デザインパターン(設計の定石)です。
以下のGameManagerスクリプトは、DontDestroyOnLoadとシングルトンパターンを組み合わせた、実践的なコード例です。
using UnityEngine;
public class GameManager : MonoBehaviour
{
// 外部からアクセスするための静的なインスタンス
public static GameManager Instance { get; private set; }
void Awake()
{
// 既にインスタンスが存在するかチェック
if (Instance != null && Instance != this)
{
// 既に存在するなら、新しく生成された自分自身を破棄して重複を防ぐ
Destroy(this.gameObject);
return;
}
// インスタンスが存在しない場合、自分自身をInstanceとして設定
Instance = this;
// シーンを跨いでも破棄されないように設定
DontDestroyOnLoad(this.gameObject);
Debug.Log("GameManagerが初期化され、永続化されました。");
}
// 例:どこからでもアクセスできるゲーム状態管理メソッド
public void AddScore(int amount)
{
// スコア加算処理など
Debug.Log("スコアが" + amount + "点加算されました。");
}
}
このコードのポイントは、Awake()内で既存のインスタンスの有無を確認し、もし既に存在していれば新しく生成された自分自身を即座に破棄している点です。これにより、シーンを何度ロードしてもGameManagerは一つしか存在しないことが保証されます。
他のスクリプトからは、GameManager.Instance.AddScore(100);のように、いつでも安全にこのマネージャーにアクセスできるようになります。
まとめ
DontDestroyOnLoadは、Unityで永続的なオブジェクトを管理するための強力なツールです。この記事で学んだ重要なポイントをまとめます。
- DontDestroyOnLoadの役割: シーンが切り替わっても、特定のGameObjectを破棄されずに保持するために使用します。BGMやゲームマネージャーなどの永続的なデータ管理に適しています。
- 基本的な使い方: 永続化したいオブジェクトにアタッチされたスクリプトの
Awake()内でDontDestroyOnLoad(this.gameObject)を呼び出します。 - 最大の注意点:
DontDestroyOnLoadを単独で使用すると、シーンを切り替えるたびにオブジェクトが重複して生成され、バグの原因となる可能性があります。 - 実践的な解決策: オブジェクトの重複を防ぎ、ゲーム全体でインスタンスが一つであることを保証するために、
DontDestroyOnLoadとシングルト ンパターンを組み合わせて使用するのが最も推奨される方法です。 - アクセス方法: シングルトン化することで、
クラス名.Instanceを通じて、ゲーム内のどこからでも安全かつ簡単に永続オブジェクトにアクセスできるようになります。
これらの知識を活用することで、あなたのUnityプロジェクトにおけるシーン管理とオブジェクトの永続化は、より洗練されたものになるでしょう。快適なゲーム開発をお楽しみください。