【Unity】シーンを切り替えてもBGMを鳴らし続ける

シーンを切り替えると切り替え前のゲームオブジェクト(もちろんコンポーネントも)アンロードされます
なので、AudioSoueceコンポーネントをアタッチしてBGMを流していてもシーン切り替えで切れることになります

継続して鳴らす方法についてみていきましょう

サンプルシーン構成

2つのシーンを用意します

1つは、切り替え前を想定したシーンで、AudioSouceコンポーネントがアタッチされ、サウンドを再生していることをシミュレートします

もう1つは、切り替え後のシーンでシーンを作成したのみです

切り替え前シーン

ここでは省略していますが、AudioClipプロパティにサウンド音源をアウトレット接続すると再生されることになります

切り替え後シーン

単純にシーンを作成しただけです
当然、AudioSouceコンポーネントは存在しません

コード

切り替え前シーンの空のゲームオブジェクトにアタッチするスクリプトになります
エディターを実行すると、シーンが切り替わります

using UnityEngine;
using UnityEngine.SceneManagement;

public class DontDestroyOnLoadSample : MonoBehaviour
{
    void Start()
    {
        SceneManager.LoadScene("NextScene");
    }
}

実行結果

見事にAudioSouceコンポーネントが消滅しています

シーン切り替え後もサウンドを途切れさせない

コードを次のように更新します

using UnityEngine;
using UnityEngine.SceneManagement;

public class DontDestroyOnLoadSample : MonoBehaviour
{
    void Start()
    {
        DontDestroyOnLoad(gameObject);

        SceneManager.LoadScene("NextScene");
    }
}

シーンが切り替わっても特定のゲームオブジェクトは削除されないようにするメソッド

次のコードは、特定のゲームオブジェクトをシーン間で破棄されないようにするために使用されます。

DontDestroyOnLoad(gameObject); 

現在のゲームオブジェクトを破棄されないようにマークします
次のシーンに移行してもこのゲームオブジェクトは維持されます

このスクリプトは、特定のゲームオブジェクトを1つのシーンから別のシーンに持ち越すために使用されます。たとえば、プレイヤーキャラクターをゲーム全体で維持したい場合などに役立ちます。

実行結果

更新前シーンのゲームオブジェクトとともにAudioSoueceコンポーネントも維持されている様子がわかります

同じシーンを再読み込みすると・・・

開始シーンは、SampleSceneですが、さらにSampleSceneのロード、つまり、今のシーンをリスタートする場合を考えてみましょう
シーンをクリアすると次のシーンへ移行するケースとともに、同じシーンをリトライする選択もできる場合など、再度同じシーンを読み込むケースなどはあり得ることですね

using UnityEngine;
using UnityEngine.SceneManagement;

public class DontDestroyOnLoadSample : MonoBehaviour
{
    void Start()
    {
        DontDestroyOnLoad(gameObject);
        SceneManager.LoadScene("SampleScene");
    }
}

実行結果

シーンがロードされるたびに、このスクリプトが実行される(つまりStartメソッドが何回も実行される)ので、新しく維持されたゲームオブジェクトがいくつも作成されます

シングルトンパターンの登場

解決策ですが、2回目以降呼び出された時、すでに存在していれば無視をするようにする方法があります

次のコードを見てください

using UnityEngine;
using UnityEngine.SceneManagement;

public class SingletonSample : MonoBehaviour
{
    private static SingletonSample instance;

    private void Awake()
    {
        if (instance == null)
        {
            // このオブジェクトがシングルトンのインスタンスとして設定される
            instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            // 既にインスタンスが存在する場合、このオブジェクトを破棄
            Destroy(gameObject);
        }
    }

    private void Start()
    {
        SceneManager.LoadScene("NextScene");
    }
}

このコードでは、Awakeメソッド内でシングルトンパターンが実装されています。AwakeメソッドはStartメソッドよりも早く呼び出され、インスタンスが生成された直後に実行されます。そのため、このメソッド内で他のインスタンスが存在するかどうかをチェックし、存在しない場合にシングルトンのインスタンスとして設定します。既にインスタンスが存在する場合、新たに生成されたオブジェクトを破棄します。

このようにすることで、シーン間を移動しても一つのインスタンスしか存在しないようになり、シングルトンパターンが実現されます。