見出し画像

UnityのDontDestroyOnLoadとは?シーンを移動しても消えないオブジェクトを作る方法

Unityでゲームを作っていると、シーンを切り替えたときに

「BGMが止まってしまう」
「スコアを次のシーンに持ち越したい」
「GameManagerを毎回作り直したくない」

という場面が出てきます。

通常、Unityでは新しいシーンを読み込むと、今のシーンにあるオブジェクトは破棄されます。
Unity公式ドキュメントでも、新しいSceneを読み込むと現在のSceneオブジェクトは破棄され、残したい場合は DontDestroyOnLoad を使うと説明されています。

そこで使うのが、今回のテーマである

DontDestroyOnLoad(gameObject);

です。



DontDestroyOnLoadとは

DontDestroyOnLoad は、シーンを切り替えても指定したオブジェクトを消さずに残すための命令です。

たとえば、TitleScene から GameScene に移動したとします。
通常は、TitleScene にあったオブジェクトは消えます。

TitleScene
・TitleCanvas
・TitleButton
・BGM

GameScene に移動すると、TitleScene のオブジェクトは基本的にすべて消えます。

GameScene
・Player
・Enemy
・Stage

しかし、BGMに DontDestroyOnLoad を使っておくと、シーンを移動してもBGMだけは残ります。

GameScene
・Player
・Enemy
・Stage
・BGM ← 消えずに残る

つまり、DontDestroyOnLoadは「シーンをまたいで使い続けたいオブジェクトに使う機能」と考えると分かりやすいです。


基本の書き方

基本の書き方はとてもシンプルです。

using UnityEngine;

public class DontDestroySample : MonoBehaviour
{
    void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

ポイントは、Awake の中に書いているところです。
DontDestroyOnLoad は Start に書いても動く場合があります。
ただし、BGMManagerのような管理用オブジェクトでは、Awake に書く方が安全です。

Awake は Start より先に呼ばれるため、他の処理が始まる前に
「このオブジェクトを残すか」
「すでに同じオブジェクトがあるなら消すか」を決められます。

そのため、DontDestroyOnLoadを使うManager系の処理は、基本的に Awake に書くのがおすすめです。
このことでシーン切り替えの前に「このオブジェクトは消さないでください」とUnityに伝えることができます。

Awake や Start の詳細はこちらの記事で


よく使う例:BGMをシーン間で流し続ける

DontDestroyOnLoadの代表的な使い方が、BGMの管理です。

タイトル画面からゲーム画面に移動しても、同じBGMを流し続けたい場合に便利です。

まず、空のGameObjectを作成します。
名前は分かりやすく BGMManager などにしておきます。

そこに AudioSource を追加し、流したい音楽を設定します。

次に、以下のスクリプトを作成します。

using UnityEngine;

public class BGMManager : MonoBehaviour
{
    void Awake()
    {
        DontDestroyOnLoad(gameObject);
    }
}

このスクリプトを BGMManager に追加します。

これで、シーンを切り替えても BGMManager は消えず、BGMも流れ続けます。


BGMの重複対応

しかしこのまま起動してしまうと、シーンを戻ったときにBGMが二重に再生される、という問題が発生する場合があります。

たとえば、TitleScene に BGMManager を置いていたとします。
TitleScene から GameScene へ移動すると、BGMManager は残ります。

その後、GameSceneからTitleSceneへ戻ったとき、TitleScene にはもともと配置していた BGMManager がまた存在しています。

つまり、
1,最初のBGMManager
2,戻ったときに新しく作られたBGMManager
この2つが同時に存在してしまいます。

その結果、BGMが二重に流れたり、音が大きくなったりします。


BGMの重複を防ぐサンプル

そこで、すでにBGMManagerが存在している場合は、新しく作られた方を削除します。

using UnityEngine;

public class BGMManager : MonoBehaviour
{
    static BGMManager instance;

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

このコードでは、instance という変数を使って、すでにBGMManagerが存在しているかを確認しています。

最初に作られたBGMManagerの場合は、instance が空なので、そのまま残します。

instance = this;
DontDestroyOnLoad(gameObject);

2つ目以降のBGMManagerが作られた場合は、すでに instance が入っているので、新しく作られた方を削除します。

Destroy(gameObject);

これで、BGMManagerが1つだけ残るようになります。


コードの考え方

static BGMManager instance;

static を使うと、シーンを移動しても共通で使える変数になります。
今回は「BGMManagerはすでに存在しているか?」を確認するために使っています。

イメージとしては、次のような感じです。

instance が空
→ まだBGMManagerはない
→ このBGMManagerを残す

instance に入っている
→ すでにBGMManagerがある
→ 新しく作られた方を消す

DontDestroyOnLoadでBGMを扱うときは「重複防止のために、この形をセットで使う」と覚えておくと実用的です。


DontDestroyOnLoadを使う場面

DontDestroyOnLoadは、次のような場面でよく使います。

  • BGMをシーン間で流し続けたい

  • スコアや残機を次のシーンに引き継ぎたい

  • GameManagerをシーンごとに作り直したくない

  • 設定データをゲーム全体で管理したい

  • フェード用のCanvasをシーン間で使いたい

DontDestroyOnLoad を初めて使用する場合は、まずは 今回紹介したBGM管理で使ってみるのがおすすめです。
動きが分かりやすく、実用性も高いです。


注意点

DontDestroyOnLoadは便利ですが、何でもかんでも使えばよいわけではありません。
シーンを切り替えても残るということは、逆に言えば「自分で消さない限り残り続ける」ということです。
必要のないオブジェクトまで残してしまうと、あとで管理がややこしくなります。

最初のうちは「シーンをまたいで本当に必要なものだけに使う」と考えておくとよいでしょう。


Unity初心者向けの記事をテーマ別にまとめています。

▼ Unity初心者向け記事まとめはこちら


こちらのマガジン「ミニゲーム作成講座 全8回セット」でもシーンの切り替えなどを活用して、初心者でも知識ゼロから作れるミニゲーム作成講座を紹介しています。

さらにステップアップの「スマホで遊ぶジャンプゲーム 8回セット」のマガジンもぜひご活用ください。


ファイブボックスでは、スクラッチやUnityの個別指導のオンラインレッスンを行っています。

ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。

いいなと思ったら応援しよう!

ファイブボックス よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!