Muzică de fundal în buclă cu introducere

Pagina actualizată :
Data creării paginii :

Mediul de verificare

Windows
  • Ferestre 11
Unity Editor
  • 2021.3.3F1
Pachet sistem de intrare
  • 1.3.0

Cerințe preliminare pentru acest sfat

Următoarele setări au fost făcute în avans ca premisă pentru descrierea acestui sfat.

Despre materialul inclus în eșantion

BGM este împrumutat de pe următorul site.

Despre fișierul audio al buclei cu introducere

De data aceasta, numai funcția standard Unity va reda o buclă cu o introducere, dar aceasta nu este acceptată ca funcție standard. În primul rând, specificațiile buclei cu introducere ca fișier audio nu sunt fixe, astfel încât metoda de creare diferă în funcție de cadrul jocului.

De data aceasta, vom pregăti două fișiere audio pentru partea "intro" și partea "loop", vom reda partea introductivă o dată și vom reda partea buclă în mod repetat. Prin urmare, vă rugăm să pregătiți cele două fișiere de mai sus ca fișiere audio.

Unele site-uri de distribuție iau în considerare acest lucru și distribuie fișiere audio separat în avans. Dacă nu, trebuie să-l faceți singur cu un instrument de editare vocală.

Dacă doriți să împărțiți fișierul în două, vă recomandăm următorul format al fișierului audio.

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

Pentru mai multe informații, consultați documentația oficială a Unității.

Despre redarea muzicii de fundal în buclă cu introducere

Creați o interfață de utilizare care vă permite să redați, să întrerupeți și să opriți muzica de fundal ca eșantion. Are același aspect ca un eșantion normal de redare a muzicii de fundal.

Adăugați două fișiere audio la proiectul dvs., împărțite în două părți, o introducere și o buclă.

De data aceasta, vom crea propriul nostru program pentru a reda BGM în buclă cu introducerea. Creați un script și lăsați-l numit IntroLoopAudio .

Scenariul arată astfel: Mă refer la codul de pe următorul site, dar am adăugat mult cod pentru că nu a funcționat bine cu WebGL și am vrut puțin mai mult control.

[Referință] 【Unitate】Implementați 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;
  }
}

Deoarece codul este lung, voi omite detaliile, dar am setat introducerea și bucla AudioClip în avans, Când începeți să jucați, redați mai întâi introducerea. Pentru bucle, programați-le să se redea când se termină introducerea. Odată ce bucla începe să se joace, redați-o în mod repetat.

Inițial, pentru bucle, a fost suficient să setați true proprietatea la , loop dar nu a funcționat corect în WebGL. AudioSource Pregătesc două bucle și le schimb alternativ pentru a juca. Dacă nu trebuie să luați în considerare WebGL, puteți reduce codul la jumătate.

După ce creați un script, îl atașați la un obiect. În mod normal, poate fi mai bine să creați un obiect gol și să îl atașați, dar este supărător, așa că atașați-l la EventSystem.

Există elemente de introducere și buclă, așa că aruncați și setați fișierul audio.

În acest moment, nu este necesară o prelucrare specială. Vreau să-l procesez când fac clic pe buton, așa că creez un script (ButtonEvent) pentru buton.

Scenariul arată astfel:

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 din inspector și adăugați acțiuni pentru fiecare buton.

Scriptul este atașat la EventSystem. Deoarece trebuie să setați Intro Loop Audio, setați EventSystem care are Intro Loop Audio.

Acum atribuiți metode evenimentelor de clic ale celor trei butoane.

Odată ce totul este configurat, rulați jocul și încercați să îl jucați. Când redarea se termină până la sfârșit, puteți vedea că se repetă din mijlocul melodiei și se redă. Desigur, acest lucru presupune că datele audio sunt bine împărțite și buclele sunt conectate perfect.

Afișarea duratei curente

Ca bonus de aici, am adăugat o proprietate care ne permite să obținem timpul de redare curent în ,IntroLoopAudio așa că haideți să o afișăm.

Mai întâi, plasați textul pentru a afișa ora.

Creați un 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}";
  }
}

Atașați un script la text și setați EventSystem cu IntroLoopAudio.

Rulați-l și vedeți dacă este afișat timpul de redare curent. De asemenea, atunci când faceți buclă, încercați să verificați dacă timpul revine la punctul de buclă.