Musica di sottofondo in loop con intro

Pagina aggiornata :
Data di creazione della pagina :

Ambiente di verifica

Finestre
  • Windows 11
Unity Editor
  • 2021.3.3f1
Pacchetto del sistema di input
  • 1.3.0

Prerequisiti per questo suggerimento

Le seguenti impostazioni sono state effettuate in anticipo come premessa per la descrizione di questo suggerimento.

Informazioni sul materiale incluso nell'esempio

BGM è preso in prestito dal seguente sito.

Informazioni sul file audio del loop con intro

Questa volta, solo la funzione Unity standard riprodurrà un ciclo con un'introduzione, ma questa non è supportata come funzione standard. In primo luogo, le specifiche del loop con intro come file audio non sono fisse, quindi il metodo di creazione differisce a seconda del framework di gioco.

Questa volta, prepareremo due file audio per la parte "intro" e la parte "loop", riprodurremo la parte introduttiva una volta e suoneremo ripetutamente la parte in loop. Pertanto, si prega di preparare i due file sopra come file audio.

Alcuni siti di distribuzione considerano questo e distribuiscono i file audio separatamente in anticipo. In caso contrario, è necessario farlo da soli con uno strumento di modifica vocale.

Se si desidera dividere il file in due, si consiglia il seguente formato del file audio.

  • OggVorbis (.ogg)
  • WAV (.wav)

Per ulteriori informazioni, consulta la documentazione ufficiale di Unity.

Informazioni sulla riproduzione in loop di musica di sottofondo con intro

Creare un'interfaccia utente che consenta di riprodurre, mettere in pausa e interrompere la musica di sottofondo come campione. Ha lo stesso layout di un normale campione di riproduzione di musica di sottofondo.

Aggiungi due file audio al tuo progetto, divisi in due parti, un'introduzione e un loop.

Questa volta, creeremo il nostro programma per riprodurre il BGM in loop con l'intro. Creare uno script e lasciarlo denominato IntroLoopAudio .

Lo script è simile al seguente: Mi riferisco al codice sul seguente sito, ma ho aggiunto molto codice perché non funzionava bene con WebGL e volevo un po 'più di controllo.

[Riferimento] 【Unity】 Implementa Intro + Loop Play - 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;
  }
}

Poiché il codice è lungo, ometterò i dettagli, ma ho impostato l'introduzione e il ciclo AudioClip in anticipo, Quando inizi a giocare, riproduci prima l'introduzione. Per i loop, programmali per la riproduzione al termine dell'introduzione. Una volta che il loop inizia a suonare, riproducilo ripetutamente.

Originariamente, per i loop, era sufficiente impostare la true proprietà su , loop ma non funzionava correttamente in WebGL. AudioSource Preparo due loop e li cambio alternativamente per giocare. Se non devi prendere in considerazione WebGL, puoi dimezzare il codice.

Dopo aver creato uno script, è possibile associarlo a un oggetto. Normalmente, potrebbe essere meglio creare un oggetto vuoto e collegarlo, ma è problematico, quindi collegarlo a EventSystem.

Ci sono elementi introduttivi e loop, quindi rilascia e imposta rispettivamente il file audio.

A questo punto, non è richiesta alcuna elaborazione speciale. Voglio elaborarlo quando faccio clic sul pulsante, quindi creo uno script (ButtonEvent) per il pulsante.

Lo script è simile al seguente:

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 dall'ispettore e aggiungi azioni per ogni pulsante.

Lo script è collegato a EventSystem. Poiché è necessario impostare Intro Loop Audio, impostare l'EventSystem che ha Intro Loop Audio.

Ora assegna metodi agli eventi di clic dei tre pulsanti.

Una volta impostato tutto, esegui il gioco e prova a giocarci. Quando la riproduzione termina fino alla fine, puoi vedere che si ripete dal centro del brano e viene riprodotto. Naturalmente, questo presuppone che i dati audio siano ben divisi e che i loop siano collegati ordinatamente.

Visualizzare la durata corrente

Come bonus da qui, abbiamo aggiunto una proprietà che ci consente di ottenere il tempo di riproduzione corrente in ,IntroLoopAudio quindi visualizziamolo.

Innanzitutto, posiziona il testo per visualizzare l'ora.

Creare uno script.

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}";
  }
}

Allegare uno script al testo e impostare EventSystem con IntroLoopAudio.

Eseguilo e verifica se viene visualizzato il tempo di riproduzione corrente. Inoltre, durante il loop, prova a verificare se l'ora ritorna al punto di loop.