前提・実現したいこと
android向けのゲームを作っている途中ですが、(縦STG)
タイトルのシーンでBGMを流した後、それがほかのシーンに遷移してもBGMが途切れることなく流れ続けてほしいのですが、
途切れてしまいます
ほかのサイトを参考にしたサウンド管理クラスをアレンジすればその辺も調整できる気がするのですが、
いかんせんソースが複雑すぎて初心者にはちょっとわからないです・・・
SE再生やBGM再生などの面で高機能(らしい?)ので、できればこの管理クラスを使ってみたいです
参考サイト:https://qiita.com/2dgames_jp/items/20360f9797c7e8b166bc#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89
どこをどのように直せばBGMのon/offをシーンをまたいで管理できるようになるのでしょうか?><
また、既存の使用方法から変更する必要がある場合は、使い方まで合わせて教えていただけるとありがたいです><
該当のソースコード
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// サウンド管理
public class Sound {
/// SEチャンネル数
const int SE_CHANNEL = 4;
/// サウンド種別
enum eType {
Bgm, // BGM
Se, // SE
}
// シングルトン
static Sound _singleton = null;
// インスタンス取得
public static Sound GetInstance() {
return _singleton ?? (_singleton = new Sound());
}
// サウンド再生のためのゲームオブジェクト
GameObject _object = null;
// サウンドリソース
AudioSource _sourceBgm = null; // BGM
AudioSource _sourceSeDefault = null; // SE (デフォルト)
AudioSource[] _sourceSeArray; // SE (チャンネル)
// BGMにアクセスするためのテーブル
Dictionary<string, _Data> _poolBgm = new Dictionary<string, _Data>();
// SEにアクセスするためのテーブル
Dictionary<string, _Data> _poolSe = new Dictionary<string, _Data>();
/// 保持するデータ
class _Data {
/// アクセス用のキー
public string Key;
/// リソース名
public string ResName;
/// AudioClip
public AudioClip Clip;
/// コンストラクタ
public _Data(string key, string res) {
Key = key;
ResName = "Sounds/" + res;
// AudioClipの取得
Clip = Resources.Load(ResName) as AudioClip;
}
}
/// コンストラクタ
public Sound() {
// チャンネル確保
_sourceSeArray = new AudioSource[SE_CHANNEL];
}
/// AudioSourceを取得する
AudioSource _GetAudioSource(eType type, int channel = -1) {
if (_object == null) {
// GameObjectがなければ作る
_object = new GameObject("Sound");
// 破棄しないようにする
GameObject.DontDestroyOnLoad(_object);
// AudioSourceを作成
_sourceBgm = _object.AddComponent<AudioSource>();
_sourceSeDefault = _object.AddComponent<AudioSource>();
for (int i = 0; i < SE_CHANNEL; i++) {
_sourceSeArray[i] = _object.AddComponent<AudioSource>();
}
}
if (type == eType.Bgm) {
// BGM
return _sourceBgm;
}
else {
// SE
if (0 <= channel && channel < SE_CHANNEL) {
// チャンネル指定
return _sourceSeArray[channel];
}
else {
// デフォルト
return _sourceSeDefault;
}
}
}
// サウンドのロード
// ※Resources/Soundsフォルダに配置すること
public static void LoadBgm(string key, string resName) {
GetInstance()._LoadBgm(key, resName);
}
public static void LoadSe(string key, string resName) {
GetInstance()._LoadSe(key, resName);
}
void _LoadBgm(string key, string resName) {
if (_poolBgm.ContainsKey(key)) {
// すでに登録済みなのでいったん消す
_poolBgm.Remove(key);
}
_poolBgm.Add(key, new _Data(key, resName));
}
void _LoadSe(string key, string resName) {
if (_poolSe.ContainsKey(key)) {
// すでに登録済みなのでいったん消す
_poolSe.Remove(key);
}
_poolSe.Add(key, new _Data(key, resName));
}
/// BGMの再生
/// ※事前にLoadBgmでロードしておくこと
public static bool PlayBgm(string key) {
return GetInstance()._PlayBgm(key);
}
bool _PlayBgm(string key) {
if (_poolBgm.ContainsKey(key) == false) {
// 対応するキーがない
return false;
}
// いったん止める
_StopBgm();
// リソースの取得
var _data = _poolBgm[key];
// 再生
var source = _GetAudioSource(eType.Bgm);
source.loop = true;
source.clip = _data.Clip;
source.Play();
return true;
}
/// BGMの停止
public static bool StopBgm() {
return GetInstance()._StopBgm();
}
bool _StopBgm() {
_GetAudioSource(eType.Bgm).Stop();
return true;
}
/// SEの再生
/// ※事前にLoadSeでロードしておくこと
public static bool PlaySe(string key, int channel = -1) {
return GetInstance()._PlaySe(key, channel);
}
bool _PlaySe(string key, int channel = -1) {
if (_poolSe.ContainsKey(key) == false) {
// 対応するキーがない
return false;
}
// リソースの取得
var _data = _poolSe[key];
if (0 <= channel && channel < SE_CHANNEL) {
// チャンネル指定
var source = _GetAudioSource(eType.Se, channel);
source.clip = _data.Clip;
source.Play();
}
else {
// デフォルトで再生
var source = _GetAudioSource(eType.Se);
source.PlayOneShot(_data.Clip);
}
return true;
}
}
追記
GameSystem.csはタイトルのシーン全体にobjectとして持っていたので、(つまりゲーム全体にかかっていた?)
新しく下記TitleControllerをタイトルシーンにのみアタッチしてStart()でPlayBgmするようにしてみましたが、
それでもなぜかアタッチしてないはずの別シーンに遷移するとBGMが一回切れて再度流れてしまいました・・・
これは、コードを変更したら一回どこかをクリーンする必要があるとか、そういう話なのでしょうか?。。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TitleController : MonoBehaviour {
// Use this for initialization
void Start () {
Sound.LoadBgm("bgm01", "test_bgm01");
Sound.PlayBgm("bgm01");
}
// Update is called once per frame
void Update () {
}
}
試したこと
シングルトンにすればいい、や、DontDestoyメソッド?を使えばシーンをまたげると調べたのですが、
サウンド管理クラス中ですでにどちらも使っているにもかかわらず、
BGMを再生するとシーンをまたいだタイミングでBGMがいったんきれるので、お手上げです。。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
タイトルに「再再生しないようにしたい」とありますが、本文にある「BGMが途切れることなく流れ続けてほしいのですが、途切れてしまいます」というのは「シーンを切り替えると再生中の曲が一旦停止し、同じ曲がまた頭から再生されてしまう」という意味でいいでしょうか?
もしかして、タイトルシーンだけでなく移動先のシーンでもSound.PlayBgm("再生したいオーディオ名");
を行ってしまってはいないでしょうか。
見たところ、このPlayBgm
は「現在どんなBGMが再生されているかは関知せず、問答無用で次のBGMを再生する」といった仕様になっているようです。
もし移動先のシーンでPlayBgm
を使っているのであればそれをやめるか、あるいはSound
スクリプトに現在セットされているオーディオクリップを調べて、再生しようとしているオーディオクリップがそれと同一であれば再再生しないようにしてみてはいかがでしょう。
/// BGMの再生
/// ※事前にLoadBgmでロードしておくこと
public static bool PlayBgm(string key)
{
return GetInstance()._PlayBgm(key);
}
bool _PlayBgm(string key)
{
if (this._poolBgm.ContainsKey(key) == false)
{
// 対応するキーがない
return false;
}
// リソースの取得
var _data = this._poolBgm[key];
// オーディオソースの取得
var source = this._GetAudioSource(eType.Bgm);
// 要求されたBGMと同一のオーディオクリップがセット済みならば、再生を続行
if (_data.Clip == source.clip)
{
return true;
}
// いったん止める
this._StopBgm();
// 再生
source.loop = true;
source.clip = _data.Clip;
source.Play();
return true;
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.36%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2018/09/17 16:25
はい、シーンが切り替わっても同じ曲の場合は同じ曲が流れ続けることを期待してましたが、そうならなかったので><;
GameSystem.csというもののstart()にPlayBgm()の処理を書いて、
それをタイトルのシーンのcanvasにのみアタッチしてました
ただそうするとなぜかタイトルでないシーンに移動してももう一回start()が動いて?しまって、最初から同じbgmが流れてしまいます。。
回答に書いていただいたもので、PlayBgm()を書き換えてみましたが、それでも結果が変わらず、でした。。
2018/09/17 17:47
なかなかやっかいそうな問題ですね...念のため、PlayBgmを使っている側のコード(GameSystem.cs)の方も見てみたいのですが、よろしいでしょうか?もし質問欄に字数制限などで追記できないようでしたら、代わりに回答欄への書き込みでもかまいません。
2018/09/17 17:59
なので、サウンド管理クラス以外に問題がある可能性が高いかもしれません…。。
すいません、家に帰り次第PlayBgmをコールしているスクリプトの方も貼ります><
2018/09/17 19:35
アタッチしてないはずのシーンで別なコントローラのStart()が呼ばれている状態です・・・情報が自動的に更新・繁栄されるわけではないのでしょうか。。
2018/09/18 05:20
実際のところ、私が試したのもまさしくご提示のTitleControllerと同様に、Start内でロード・再生を行うものでした。
Unityのプロジェクトに何か不具合が生じているのでもない限り、外部エディタで加えた変更がUnityに戻った際に自動的に反映されないということはなさそうに思います。「Assets」→「Reimport All」で全アセットをインポートし直してみるとか、新規にプロジェクトを作って、TitleControllerのようなシンプルなコードだけで実験を行った場合にBGM再再生現象が起きるかは確認済みでしょうか?
もし新規プロジェクトで試しても現象が発生するなら、ご質問者さんの環境特有の問題かもしれません。Unityのバージョンが古いなら最新版に更新してみるなど、手探りで解決することになるかもしれませんね...
2018/09/18 20:28
これはやってみましたが、結果が変わらずでした。。
新規にプロジェクトを作って~というのは、オブジェクトを1から作り直したりするのが手間なのでやってません。。
シーン遷移させる必要がある以上、どっちにしろシンプルにはできないかと思ってて。。
unityのverは2017.4.1f1でした
2018/09/18 20:48
デバッグのやり方もいまいちわからないので、挙動がおかしいのであれば、シーンを遷移させたときにどこのどの変数の値を見ればよいのか(何が正しいのか)という期待値を教えてもらいたいです・・
もしくは原因となりそうな悪そうな設定など、心当たりがあれば教えてもらいたいです、、
2018/09/18 20:57
どちらのシーンから実行しても二つのBGMが同時に流れ始めるようになりました(シーン遷移すると二つのBGMが両方とも再再生しだすのは変わらず)
一つのシーンを始めると、ほかのシーンのコントローラーのStart()もすべて実行してしまうものなのでしょうか?unityとは。。
2018/09/19 04:39
Visual Studioの場合でしたら、「【Unity】デバッグのやり方入門」(https://qiita.com/john95206/items/03da8626583957bf1a1c )や「Visual Studio Tools for Unity を使用する - Visual Studio | Microsoft Docs」(https://docs.microsoft.com/ja-jp/visualstudio/cross-platform/using-visual-studio-tools-for-unity?view=vs-2017 )がご参考になりそうです。
これならコード内の特定の行...たとえば「_PlayBgm」メソッドの最初の行にブレークポイントを設置して、「Unityにアタッチ」でデバッガを動かした状態でUnityに戻りプレイモードにすると、該当する行に到達したところで実行が一時停止するので、そこでVisual Studioを見てみると、その時点の様々な変数の内容を見てみたり、一行ずつ実行を進めてみたりできて便利です。
もっと単純な方法では、やはりコード内の各所に「Debug.Log(...」を入れて、コンソールにメッセージを表示させてみることかと思います。
PlayBgmは最初のシーンのStartで1回だけ行うように戻して、「_PlayBgm」メソッドに入った直後の行に「Debug.Log("_PlayBgm key:" + key);」などと入れ、その状態で実行するとどうなるでしょうか?
シーンを移動した際に、本当にStartやPlayBgmが再実行されてしまうのであれば、シーン移動時にコンソールに2回目のメッセージが表示されてしまうはずです(実際のところ、シーン移動によって別のシーンのStartが実行されてしまうとは考えにくいので、メッセージはプレイ開始直後の1回だけだろうとは思うのですが...)。
すみませんが私としてもかなり予想外の症状で、どういう動作でそのような挙動になるのか見当の付かない状況です...
第2のシーンで別のBGMを流すと、第1のシーンのBGMと一緒に重なって鳴ってしまうというのも奇妙です。理想的には、最初のシーンのPlayBgm実行でヒエラルキービューに「DontDestroyOnLoad」という名前のシーンが出現し、その中には「Sound」という名前のゲームオブジェクトがあり、それに6つのAudioSourceがアタッチされているはずです。
これらのうち1つがBGM用のAudioSourceで、BGMはこのAudoSourceだけから鳴らされており、再生時にPlayOneShotを使っているわけでもないので、複数のBGMが重なって鳴ることはないはずです。
プレイ中、ヒエラルキー上のオブジェクトはどうなっているでしょうか?「Sound」が複数個出現したり、一瞬消えたり...といった変な挙動はないでしょうか(このSoundクラスはそうならないよう作られているはずなので、これもおそらく違う気がしますが...)。
また、何かアセットを導入していますでしょうか?私の方では現象が再現できない状況でして、なるべく条件を同じにするための参考にしたいのです。
実験もまだUnity 2018.2.8f1でしか試していませんので、のちほど2017.4.1f1だとどうなるか試してみようと思います。
2018/09/19 14:05
Debug.Logは家に戻り次第実行してみたいと思います><(本業はゲーム開発とはほぼ無縁な初心者です。。)
ちなみに2度メッセージが表示される場合、どのような原因がありえるのでしょうか?
一つのコントローラーが二つ以上のシーンにアタッチされている、とか?
以前別問題でLogを出した際に2回通っているような出方をした気がして・・
はい、プレイ中はヒエラルキービューにDontDestroyOnLoadが出現します
Soundも一つだけで、一瞬消えたりもなかったと思います。。
シーン遷移時もDontDestroyOnLoadが一つだけあるってのは変わらなかったです
AssetStoreからでしょうか?
このプロジェクトでは、ストアからは何も導入してないです
Unity 2018.2.8f1のほうが新しいのであれば、そこまでアップデートしたほうがよいのでしょうか?解決するかは別にして。。
2018/09/20 01:04
ソースからPlayBgm("bgm02")は消したにも関わらず、bgm01と02が同時に流れ始めました。。
どうもResource/Soundフォルダの下にbgm01と02が入っていてそれがオブジェクト(AudioSources?)としてある以上、PlayBgmのkeyに関係なくすべて再生されているように見られます・・・
プレイ中、Soundの中のAudioSourcesは確かに6つできていました。(インスペクタの詳細の意味まではわかりませんが。。)
2018/09/20 07:13
ですが、2017.4.1f1から現行バージョンまでの間にいろいろとバグフィックスが行われていますので、2017.4.1f1でないと動作しないアセットを修正を加えず使いたい...といった、2017.4.1f1のままにしておきたい明確な理由がなければ、現行バージョンにアップグレードするのが望ましいかと思います。今回のトラブルがいろいろな条件が重なって生じるレアケースであれば、直接関係なさそうなバグが修正された結果正常に動作するようになるかもしれません。
Debug.Logの結果やヒエラルキーの様子から察するに、おそらくスクリプトは想定通り正常に動作しているものと思われます。
ちなみに、もし1回しか実行されないはずのStartが別シーンでも実行されてしまうという場合は、ちょっとすぐにはいい例が思いつきませんでしたが、たとえば別シーン編集中にそのスクリプトをうっかり誤操作でシーン内オブジェクトにアタッチしてしまった...といったケースがあるかもしれません。ですが今回はそういったミスではなさそうですので、考慮する必要はないかと思います。
PlayBgm("bgm02")を消して、いずれのシーンでもbgm02が流れるはずのない状況にしたにもかかわらずbgm02が再生されるとなると、いよいよもって理解できない挙動ですね。Assets内のどこかのフォルダにAudioClipアセットの形で音楽ファイルが置かれているだけでは、それが勝手に再生されるなんてことにはならないはずです。
何か同様の事例がないか検索してみたものの、あまり有用な情報は得られませんでした。
オーディオ関連のトラブルとして「Music Stops Playing When Application Loads New Scene - Unity Forum」(https://forum.unity.com/threads/music-stops-playing-when-application-loads-new-scene.73573/ )との投稿があり、このご質問者さん自身はオブジェクトのDontDestroyOnLoadによって解決したようですが、2017年に寄せられたコメントにオーディオクリップの「Load Type」、「Compression Format」が関係するケースがあるかもしれないことが示唆されています。
私の試す限りでは、音楽ファイルの設定を適当に変えてみても問題は発生しなかったのですが、ダメもとでこれら設定を変更してみてはいかがでしょうか。
bgm02の件のような妙な現象が現れるとなると、ご質問者さんの書かれたコードやSoundクラスのコードには非はなくて、先ほど申し上げたような何らかのマイナーバグを踏んでしまった可能性が高まりそうです。
まずUnityを最新バージョンにアップグレードしてみて、それでも解決しなければ、今度はBGM再生の方法をSoundクラスのやり方とは異なる方法に変えてみるのはどうでしょう。
例えば、Soundクラスの場合はBGM再生用オブジェクトをDontDestroyOnLoadを使って生存させていますが、代わりに永続オブジェクト専用のシーンを作って、BGM再生用オブジェクトはそこに配置し、タイトルシーンやゲームシーンはロード時にLoadSceneMode.Additiveを指定して、永続シーンの上に加算的にロードしてやるとか...
2018/09/20 21:08
音楽ファイルの設定も変えて試してみましたが、だめでした・・・
すいません、Soundクラスは使ったまま、シーンのロードのところだけを変えるということでしょうか?。。
正直もうサウンド管理クラスを別な、簡単なのに変えてやってみるしかないのかな・・
2018/09/20 21:16
2018/09/21 05:57
同じ音楽をPlaySeメソッドで流していたとか、Soundクラスを使わずに独自にAudioSourceにBGMをアタッチしたオブジェクトが存在するとかでしたら、確かにPlayBgmがないのにその音楽が再生されるでしょうが、まさかそのような風にしてしまうとは考えづらいですし...
ご質問者さんさえさしつかえなければ、プロジェクトのフォルダ全体をどこかにアップロードしていただけるとさらに調査を進められるかもしれません。
もちろん、不特定多数に再利用可能な状態で配布してはいけないライセンスのデータを多数含んでいるなど、アップロードするにはかなり手間を要する場合もあるでしょうから、無理にとはもうしません。
Soundクラスの利用方法ですが、SE再生機能だけを使って、BGMは別の手段を用いることも可能のはずです。LoadBgmもPlayBgmも使わなければ、唯一BGM関連で残るのはシーン上のSoundオブジェクトにアタッチされたBGM用AudioSourceだけになりますが、このAudioSourceも何もオーディオクリップを参照していないただの不用物ですので、動作に影響はないかと思います(とはいえ、PlayBgmを削除しても音が鳴るような不可解な状況ですので、確証は持てませんが...)。
2018/09/24 18:11
原因は二つ
①「Sounds」フォルダではなく「Sound」フォルダにおいてしまっていたこと(リソースが見つけられない状態でした。。)
②ヒエラルキー上にもAudioSourceが必要だと思い置いていましたが、それのPlayOnAwakeプロパティがonになっていると、シーン開始時に自動的にAudio再生を行うようでした(実際はSoundクラスを使って再生を行えばヒエラルキー上にAudioオブジェクトは不要みたいです。。)
二つのミスが重なってしまったせいで、原因が非常にわかりづらいものになってしまっていたにも関わらず、Bongoさんには一緒に色々と原因を模索してもらって、大変ありがとうございました。。><
こちらで正常にSoundクラスを使って再生を行ってみて、実際に元のコードだとタイトルのシーンから別シーンに遷移した際にはBGMが途切れず再生するが、再度タイトルのシーンに戻った場合BGMが再再生される現象がようやく確認できました
その後、Bongoさんに改良していただいたコードで実行した場合、再度タイトルのシーンに戻ってもBGMが再再生されることなく継続して再生されることが確認できました
最終的には、Bongoさんに改良してもらった形で同じシーンに戻っても再再生されることなく再生され続けることがやりたかったことなので、(途中こちらで見ていた事象はSoundクラスを使ってさえいない状態でしたが)
やりたかったことに一致していてかつ長々と原因を調べてもらった感謝もあってBAとさせていただきますm(_ _)m
ありがとうございました!!m(_ _)m
2018/09/24 18:41