CRIWARE Unity Plugin Manual  Last Updated: 2024-12-05
シーンを越えるサウンド制御

サンプル内容

概要

シーンをまたいで音楽を流し続けたり、シーン切り替え時に音楽をクロスフェードで自然に切り替えたいなどといった目的で、シーンを越えてサウンド制御を行いたい場合があります。
本サンプルはシーンを越えるサウンド制御のためのスクリプトやオプション設定について説明します。

cri4u_samples_criatom_script03_main.png

操作方法

※シーン実行時は必ず「TitleScene」から開始してください。
  • 画面右上の[change scene]ボタン
    TitleSceneとGameSceneを相互に切り替えます。

シーン情報


ミドルウェア CRI ADX (CRI Atom)
サンプル Scriptサンプル:シーンを越えるサウンド制御
格納場所 /cri/unity/samples/UnityProject/Assets/Scenes/criatom/script/ScriptSample03_OverSceneSound/Scenes
シーンファイル ScriptSample03_TitleScene.unity
ScriptSample03_GameScene.unity
ADXデータのオリジナル データ:音楽の簡易クロスフェード


プログラムの解説

シーンを越えてサウンド制御を行うためのサンプルプロジェクトです。
手順の概要としては、最初に起動したシーンでCRI関連のオブジェクトやアプリのサウンド制御スクリプトを生成し、それをシーン終了時に破棄せずに次のシーンでも使い続けるように設定を行います。
アプリのサウンド制御はScriptSample03_SoundManagerというオブジェクトで管理して、staticな関数 ScriptSample03_SoundManager.PlayCueId() を呼び出すことでどのシーン からでもサウンド再生の呼び出しを可能にしています。
本サンプルでは各シーンの開始時にシーン専用の音楽を再生開始するようにしてあります。
サウンドデータ側で音楽の再生開始時にクロスフェードがかかる設定にしてありますので、シーンが変わっても音楽がぶつっと途切れることなく自然に切り替わります。もちろんシーンを越えてひとつの音楽を流し続けるといった実装も可能です。

シーン切り替え時にサウンド関連を破棄しないための設定

4つのオブジェクト(コンポーネント)に対して、シーン切り替え時に破棄しないための設定を行う必要があります。
(1) CriWareLibraryInitializer の"Don't Destroy On Load"チェックを「入れる」。

cri4u_samples_criatom_script03_initializer.png

(2) CriWareErrorHandler の"Don't Destroy On Load"チェックを「入れる」。

cri4u_samples_criatom_script03_error_handler.png

(3) CRIWAREオブジェクト(Cri Atom)の"Don't Destroy On Load"にチェックを「入れる」。

cri4u_samples_criatom_script03_criware.png

(4) ScriptSample03_SoundManagerスクリプトのAwake時に GameObject.DontDestroyOnLoad(this.gameObject)を実行する。
(5) ScriptSample03_SoundManagerスクリプトのAwake時に多重生成を許さないようにコードを追加する(詳細は後述)。

こうすることで、シーン切り替え時にCRI関連および ScriptSample03_SoundManager.cs が破棄されずに継続動作するようになります。
手順(5)は、最初のシーンにもう一度戻ってきた場合に ScriptSample03_SoundManager.cs が2個出来てしまわないようにするための対策です。
なお、CRIWARE Library Initializer、CRIWARE Error Handler、CRI Atom については多重生成対策済みです。

ScriptSample03_SoundManagerスクリプトの実装例

SoundManager スクリプトでは上記手順(4)(5)の実装が必要です。本サンプルを例に説明します。
手順(4)の実装は GameObject.DontDestroyOnLoad(this.gameObject) の部分です。
手順(5)の実装は isAwaked フラグに基づく GameObject.Destroy(this) の部分です。

using System.Collections;
using System.Collections.Generic;
public class ScriptSample03_SoundManager : MonoBehaviour {
/* ACB file name (CueSheet name) */
public string cueSheetName = "CueSheet_0";
private CriAtomSource atomSourceMusic;
static private ScriptSample03_SoundManager instance = null;
void Awake ()
{
if (instance != null) {
GameObject.Destroy(this);
return;
}
/* Create the CriAtomSource for BGM. */
atomSourceMusic = gameObject.AddComponent<CriAtomSource> ();
atomSourceMusic.cueSheet = cueSheetName;
/* Do not destroy the SoundManger when scenes are switched. */
GameObject.DontDestroyOnLoad(this.gameObject);
instance = this;
}
static public void PlayCueId(int cueId){
instance.atomSourceMusic.Play(cueId);
}
void OnDestroy(){
if (instance == this) {
instance = null;
}
}
}

Hierarchyに2個ずつオブジェクトが表示される症状について

本サンプルを実行すると、ScriptSample03_GameScene から ScriptSample03_TitleScene に戻った時に、Hierarchyウインドウにいくつかのオブジェクトが2つずつ表示されていることに気付くかと思います。

cri4u_samples_criatom_script03_double_object.png

これは実害ありませんので無視してください。
各オブジェクトの多重生成チェック時に、自分自身(Component)は破棄しているのですが親のゲームオブジェクト自体を破棄していないために発生している現象です。
実際、Inspectorで確認すると2個目のゲームオブジェクトの中には何もありませんし、この中身のないオブジェクトはシーンが切り替わる時に破棄されますので3つ以上にどんどん増えていくという事はありません。
中身のないオブジェクトであっても2つ表示されるのを回避するためには、多重生成判定時に親のゲームオブジェクトごと破棄する必要があります。ただしこの方法は親ゲームオブジェクトに他のコンポーネントが接続されている可能性もあり危険です。
親ゲームオブジェクト自体が常に1つしか存在しないような実装にして、それぞれのコンポーネントでは多重チェック自体が不要にするなどの対策のほうがオススメです。

任意のシーンから開始できるようにする方法について

本サンプルは、シーン破棄時や多重生成チェックに焦点をあてて説明しているため、実行開始は必ず ScriptSample03_TitleScene でなければいけないという制約がついてしまっています。
サンプル「 どのシーンからでも実行可能 」では、本サンプルを任意のシーンから実行可能にするための手順について説明してあります。

各ゲームシーンのスクリプト説明

本サンプルではサウンド再生を要求する処理自体は各シーンに固有のスクリプトから実行しています。
ScriptSample03_SoundManager.cs はシーンを越えて存在しており、さらに static な関数 SoundManager.PlayCueId() を定義してありますので、どのシーンのスクリプトからでもサウンド再生を実行することが出来ます。
本サンプルのシーン別スクリプトはとても単純で、シーン開始時に音楽の再生開始を実行しているだけです。

スクリプトファイル: Scripts/ScriptSample03_TitleScene.cs
using System.Collections;
public class ScriptSample03_TitleScene : MonoBehaviour {
private int SceneMusicCueId = 1;
private string nextSceneName = "ScriptSample03_GameScene";
/* Called before the first Update(). */
void Start () {
/* Play BGM. */
ScriptSample03_SoundManager.PlayCueId(SceneMusicCueId);
}
/* Show and control the scene-switching GUI. */
void OnGUI(){
if (Scene_00_SampleList.ShowList == true) {
return;
}
/* Set UI skin. */
GUI.skin = Scene_00_SampleList.uiSkin;
Scene_00_GUI.BeginGui("01/SampleMain");
if (Scene_00_GUI.Button(new Rect(Screen.width-250,200,150,150), "change\nscene")) {
Application.LoadLevel(nextSceneName);
}
Scene_00_GUI.EndGui();
}
}

Advanced サンプルとの違いについて

CRI ADXの [CriAtom]Advancedサンプル にある「 [CriAtom]BGM中断無しシーン切り替え 」との違いについて説明します。
どちらのサンプルもシーンを越えてサウンド再生をしたいという目的は同じです。
本サンプルが ScriptSample03_SoundManager というアプリ作成のスクリプトを使用した例なのに対して、「 [CriAtom]BGM中断無しシーン切り替え 」はスクリプト記述無しで CRI Atom Source を継続使用できるように Hierarchy を設定しています。
アプリの実装で使いやすい方法をご利用ください。