イントロのついたBGMは、だいたい以下のようなフローになると思います。
(カッコ内の秒数はイメージしやすくするための仮数値です)
- イントロ (0〜20秒地点までのメロディー)
- イントロ以降のメロディー (20秒地点以降のメロディー)
- BGM終了 (130秒地点で終了)
- ループポイントに戻って再生 (20秒地点から再生再開)
- BGM終了 (130秒地点で終了)
- ループポイントに戻って再生 (20秒地点から再生再開)
ループが延々に続く。
このイントロが存在するBGM
を最小限のコードで実装してみました。
AudioClipとBGM定義クラスのセット
まずは再生させたいAudioClipとその定義クラスが必要です。
ここで言う定義クラス
は以下の情報を保持します。
- BGM開始時間
- BGM終了時間
- BGMのループポイントの時間
この定義クラスとAudioClipがセットになったSoundInfoクラスを作り、それをSoundManagerクラスが保持します。
/// <summary> /// BGM定義クラス /// </summary> public class BgmDefine { /// <summary> /// BGMのスタート時間 /// </summary> public float startTime; /// <summary> /// ループポイント時間 /// </summary> public float loopTime; /// <summary> /// BGMの終了時間 /// </summary> public float endTime; } public class SoundInfo { public BgmDefine define; public AudioClip clip; }
BGMの再生を開始させたらSoundManagerのUpdate関数で現在のBGMの再生時間を監視し、終了時間が来たらループ時間へジャンプさせます。
void Update () { // 再生中のBGMの再生時間を監視する if (_currentBgmDefine != null && _currentBgmSource != null && _currentBgmSource.isPlaying) { if (_currentBgmSource.time >= _currentBgmDefine.endTime) { // ループポイントへジャンプ _currentBgmSource.time = _currentBgmDefine.loopTime; } } }
以下全ソースです。
Main.csは、SoundManagerに再生させたいAudioClipと定義情報を渡しています。実際に使用するのはSoundManager.csだけです。
まとめ
このサンプルだとAudioSourceが1つしか無いので同時再生BGMは出来ません。
※例えばクロスフェードでBGMが切り替わるなどの表現は出来ません。もちろんBGMを再生中にSEも鳴らすことは出来ません。
また、BGMはファイルサイズが大きいのでアセットバンドル化して外部読込するのが一般的です。
AssetBundle化する際にBGM定義クラスをJSONファイルなどにして、AudioClipと同梱させたAssetBundleを作成するような感じです。
この辺は続編で紹介していきます。
イントロ付きのBGM実装についてググってみると、イントロ部分のBGMとループ部分のBGMを別々のファイルにする実装が多いですが、本記事の実装の方が音声ファイル一つで済むので楽じゃないかなと思ったりもします。