迴圈背景音樂與介紹
驗證環境
- 窗戶
-
- 視窗 11
- 統一編輯器
-
- 2021.3.3f1
- 輸入系統包
-
- 1.3.0
此提示的先決條件
作為此提示描述的前提,已預先進行了以下設置。
關於樣品中包含的材料
BGM是從以下網站借來的。
關於帶有介紹的迴圈的音訊檔
這一次,只有標準的 Unity 函數會播放帶有介紹的迴圈,但不支援作為標準函數。 首先,將介紹作為音訊檔的循環的規格不是固定的,因此創建方法因遊戲框架而異。
這次,我們將為「介紹」部分和「迴圈」部分準備兩個音訊檔,播放一次介紹部分,並重複播放迴圈部分。 因此,請將上述兩個文件準備為音訊檔。
一些分發網站會考慮這一點並提前單獨分發音頻檔。 如果沒有,您需要使用語音編輯工具自己製作。
如果要將檔一分為二,我們建議使用以下格式的音訊檔。
- 奧格沃比斯 (.ogg)
- 波浪 (.wav)
有關更多資訊,請參閱官方 Unity 文件。
關於播放帶有介紹的迴圈背景音樂
創建一個UI,允許您播放、暫停和停止背景音樂作為範例。 它具有與普通背景音樂播放範例相同的佈局。
將兩個音訊檔添加到您的專案中,分為兩部分,一個介紹和一個迴圈。
這一次,我們將創建自己的程式來播放帶有介紹的迴圈 BGM。
建立一個文稿並將保留為 IntroLoopAudio
.
文稿如下所示: 我指的是以下網站上的代碼,但我添加了很多代碼,因為它不能很好地與 WebGL 配合使用,我想要更多的控制。
[參考資料] 【團結】實現介紹+迴圈播放 - 7080 + 1
using UnityEngine;
<summary>
イントロ付きループ BGM を制御するクラスです。
</summary>
<remarks>
WebGL では PlayScheduled で再生するとループしないのでその対応を入れている。
WebGL では2つの AudioSource を交互に再生。
</remarks>
public class IntroLoopAudio : MonoBehaviour
{
<summary>BGM のイントロ部分の音声データ。</summary>
[SerializeField] private AudioClip AudioClipIntro;
<summary>BGM のループ部分の音声データ。</summary>
[SerializeField] private AudioClip AudioClipLoop;
<summary>BGM のイントロ部分の AudioSource。</summary>
private AudioSource _introAudioSource;
<summary>BGM のループ部分の AudioSource。</summary>
private AudioSource[] _loopAudioSources = new AudioSource[2];
<summary>一時停止中かどうか。</summary>
private bool _isPause;
<summary>現在の再生するループ部分のインデックス。</summary>
private int _nowPlayIndex = 0;
<summary>ループ部分に使用する AudioSource の数。</summary>
private int _loopSourceCount = 0;
<summary>再生中であるかどうか。一時停止、非アクティブの場合は false を返す。</summary>
private bool IsPlaying
=> (_introAudioSource.isPlaying || _introAudioSource.time > 0)
|| (_loopAudioSources[0].isPlaying || _loopAudioSources[0].time > 0)
|| (_loopAudioSources[1] != null && (_loopAudioSources[1].isPlaying || _loopAudioSources[1].time > 0));
<summary>現在アクティブで再生しているループ側の AudioSource。</summary>
private AudioSource LoopAudioSourceActive
=> _loopAudioSources[1] != null && _loopAudioSources[1].time > 0 ? _loopAudioSources[1] : _loopAudioSources[0];
<summary>現在の再生時間 (s)。</summary>
public float time
=> _introAudioSource == null ? 0
: _introAudioSource.time > 0 ? _introAudioSource.time
: LoopAudioSourceActive.time > 0 ? AudioClipIntro.length + LoopAudioSourceActive.time
: 0;
void Start()
{
_loopSourceCount = 2; // WebGL でなければ 1 でもよい
// AudioSource を自身に追加
_introAudioSource = gameObject.AddComponent<AudioSource>();
_loopAudioSources[0] = gameObject.AddComponent<AudioSource>();
if (_loopSourceCount >= 2)
{
_loopAudioSources[1] = gameObject.AddComponent<AudioSource>();
}
_introAudioSource.clip = AudioClipIntro;
_introAudioSource.loop = false;
_introAudioSource.playOnAwake = false;
_loopAudioSources[0].clip = AudioClipLoop;
_loopAudioSources[0].loop = _loopSourceCount == 1;
_loopAudioSources[0].playOnAwake = false;
if (_loopAudioSources[1] != null)
{
_loopAudioSources[1].clip = AudioClipLoop;
_loopAudioSources[1].loop = false;
_loopAudioSources[1].playOnAwake = false;
}
}
void Update()
{
// WebGL のためのループ切り替え処理
if (_loopSourceCount >= 2)
{
// 終了する1秒前から次の再生のスケジュールを登録する
if (_nowPlayIndex == 0 && _loopAudioSources[0].time >= AudioClipLoop.length - 1)
{
_loopAudioSources[1].PlayScheduled(AudioSettings.dspTime + (AudioClipLoop.length - _loopAudioSources[0].time));
_nowPlayIndex = 1;
}
else if (_nowPlayIndex == 1 && _loopAudioSources[1].time >= AudioClipLoop.length - 1)
{
_loopAudioSources[0].PlayScheduled(AudioSettings.dspTime + (AudioClipLoop.length - _loopAudioSources[1].time));
_nowPlayIndex = 0;
}
}
}
public void Play()
{
// クリップが設定されていない場合は何もしない
if (_introAudioSource == null || _loopAudioSources == null) return;
// Pause 中は isPlaying は false
// 標準機能だけでは一時停止中か判別不可能
if (_isPause)
{
_introAudioSource.UnPause();
if (_introAudioSource.isPlaying)
{
// イントロ中ならループ開始時間を残り時間で再設定
_loopAudioSources[0].Stop();
_loopAudioSources[0].PlayScheduled(AudioSettings.dspTime + AudioClipIntro.length - _introAudioSource.time);
}
else
{
if (_loopSourceCount >= 2)
{
// WebGL の場合は切り替え処理を実行
if (_loopAudioSources[0].time > 0)
{
_loopAudioSources[0].UnPause();
if (_loopAudioSources[0].time >= AudioClipLoop.length - 1)
{
_loopAudioSources[1].Stop();
_loopAudioSources[1].PlayScheduled(AudioSettings.dspTime + (AudioClipLoop.length - _loopAudioSources[0].time));
_nowPlayIndex = 1;
}
}
else
{
_loopAudioSources[1].UnPause();
if (_loopAudioSources[1].time >= AudioClipLoop.length - 1)
{
_loopAudioSources[0].Stop();
_loopAudioSources[0].PlayScheduled(AudioSettings.dspTime + (AudioClipLoop.length - _loopAudioSources[0].time));
_nowPlayIndex = 0;
}
}
}
else
{
// WebGL 以外は UnPause するだけ
_loopAudioSources[0].UnPause();
}
}
}
else if (IsPlaying == false)
{
// 最初から再生
Stop();
_introAudioSource.Play();
// イントロの時間が経過した後に再生できるようにする
// 設定する時間はゲーム刑か時間での設定となる
_loopAudioSources[0].PlayScheduled(AudioSettings.dspTime + AudioClipIntro.length);
}
_isPause = false;
}
<summary>BGM を一時停止します。</summary>
public void Pause()
{
if (_introAudioSource == null || _loopAudioSources == null) return;
_introAudioSource.Pause();
_loopAudioSources[0].Pause();
if (_loopAudioSources[1] != null) _loopAudioSources[1].Pause();
_isPause = true;
}
<summary>BGM を停止します。</summary>
public void Stop()
{
if (_introAudioSource == null || _loopAudioSources == null) return;
_introAudioSource.Stop();
_loopAudioSources[0].Stop();
if (_loopAudioSources[1] != null) _loopAudioSources[1].Stop();
_isPause = false;
}
}
由於代碼很長,細節我會省略,但我提前設置了介紹和迴圈 AudioClip
,
當您開始播放時,請先播放介紹。 對於迴圈,請安排它們在介紹結束時播放。
循環開始播放后,重複播放。
最初,對於迴圈, loop
將屬性設置為 true
就足夠了,但它在WebGL中無法正常工作。
AudioSource
我準備了兩個迴圈,並交替切換它們來播放。
如果你不必考慮WebGL,你可以把你的代碼減少一半。
創建文稿后,將其附加到物件。 通常,最好創建一個空物件並附加它,但這很麻煩,因此請將其附加到 EventSystem。
有介紹和循環專案,因此請分別刪除和設置音訊檔。
此時,不需要特殊處理。
我想在按鍵時處理它,因此我為按鈕創建了一個腳本(ButtonEvent
)。
文稿如下所示:
using UnityEngine;
public class ButtonEvent : MonoBehaviour
{
[SerializeField] private IntroLoopAudio IntroLoopAudio;
public void OnClickPlay()
{
IntroLoopAudio.Play();
}
public void OnClickPause()
{
IntroLoopAudio.Pause();
}
public void OnClickStop()
{
IntroLoopAudio.Stop();
}
}
IntroLoopAudio
,然後為每個按鈕添加操作。
該腳本將附加到事件系統。 由於您需要設置介紹迴圈音訊,因此請設置具有介紹迴圈音訊的事件系統。
現在,將方法分配給三個按鈕的按兩下事件。
設置好所有內容后,運行遊戲並嘗試玩它。 當播放結束到結束時,您可以看到它從歌曲中間迴圈播放。 當然,這是假設音訊數據劃分整齊,迴圈連接整齊。
顯示當前持續時間
作為此處的獎勵,我們添加了一個屬性,IntroLoopAudio
該屬性允許我們在 中獲取當前播放時間,因此讓我們顯示它。
首先,放置文本以顯示時間。
創建腳本。
using UnityEngine;
using UnityEngine;
using UnityEngine.UI;
public class TextEvent : MonoBehaviour
{
[SerializeField] private IntroLoopAudio IntroLoopAudio;
private Text _text;
// Start is called before the first frame update
void Start()
{
_text = GetComponent<Text>();
}
// Update is called once per frame
void Update()
{
_text.text = $"AudioPlayTime : {IntroLoopAudio.time}";
}
}
將腳本附加到文本並使用IntroLoopAudio設置事件系統。
運行它並查看是否顯示當前播放時間。 此外,迴圈時,嘗試檢查時間是否返回到迴圈點。