Háttérzene hurkolása intróval

Oldal frissítve :
Oldal létrehozásának dátuma :

Ellenőrzési környezet

Windows
  • Windows 11 esetén
Unity-szerkesztő
  • 2021.3.3f1
Bemeneti rendszercsomag
  • 1.3.0

A tipp előfeltételei

A következő beállításokat előre elvégeztük a tipp leírásának előfeltételeként.

A mintához mellékelt anyagról

A BGM-et a következő oldalról kölcsönzik.

A hurok hangfájljáról intro

Ezúttal csak a szabványos Unity függvény játszik le hurkot egy bevezetővel, de ez nem támogatott szabványos függvényként. Először is, a hurok specifikációi az intro mint hangfájlként nincsenek rögzítve, így a létrehozási módszer a játék keretétől függően eltérő.

Ezúttal két hangfájlt készítünk az "intro" részhez és a "loop" részhez, egyszer játsszuk le az intro részt, és többször játsszuk le a loop részt. Ezért kérjük, készítse elő a fenti két fájlt hangfájlként.

Egyes terjesztési webhelyek ezt figyelembe veszik, és előzetesen külön terjesztik az audiofájlokat. Ha nem, akkor saját magának kell elkészítenie egy hangszerkesztő eszközzel.

Ha két részre szeretné osztani a fájlt, javasoljuk a hangfájl következő formátumát.

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

További információért tekintse meg a Unity hivatalos dokumentációját.

Információk a háttérzene lejátszásáról az intro segítségével

Hozzon létre egy felhasználói felületet, amely lehetővé teszi a háttérzene mintaként történő lejátszását, szüneteltetését és leállítását. Ugyanolyan elrendezésű, mint egy normál háttérzene-lejátszási minta.

Adjon hozzá két hangfájlt a projekthez, két részre osztva, egy bevezetésre és egy hurokra.

Ezúttal saját programot hozunk létre a looping BGM lejátszásához az intróval. Hozzon létre egy szkriptet, és hagyja meg a nevét IntroLoopAudio .

A szkript így néz ki: A következő webhelyen található kódra utalok, de sok kódot adtam hozzá, mert nem működött jól a WebGL-lel, és egy kicsit több vezérlést akartam.

[Hivatkozás] 【Unity】Intro + Loop Play megvalósítása - 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;
  }
}

Mivel a kód hosszú, kihagyom a részleteket, de előre beállítottam az intrót és a hurkot AudioClip , Amikor elkezdesz játszani, először játszd le az intrót. A hurkok esetében ütemezze őket úgy, hogy az intro végén játsszák le őket. Miután a hurok lejátszása megkezdődött, játssza le többször.

Eredetileg loop a hurkok esetében elegendő volt a true tulajdonságot -re állítani, de WebGL-ben nem működött megfelelően. AudioSource Két hurkot készítek, és felváltva váltogatom őket a játékhoz. Ha nem kell figyelembe vennie a WebGL-t, felére csökkentheti a kódot.

Miután létrehozott egy parancsfájlt, csatolja azt egy objektumhoz. Általában jobb lehet létrehozni egy üres objektumot, és csatolni, de ez zavaró, ezért csatolja az EventSystemhez.

Vannak intro és loop elemek, ezért dobja el és állítsa be az audio fájlt.

Ezen a ponton nincs szükség speciális feldolgozásra. Szeretném feldolgozni, amikor a gombra kattintok, ezért létrehozok egy szkriptet (ButtonEvent) a gombhoz.

A szkript így néz ki:

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 a vizsgálóból, és adjon hozzá műveleteket az egyes gombokhoz.

A szkript az EventSystemhez van csatolva. Mivel be kell állítania az Intro Loop Audio alkalmazást, állítsa be az Intro Loop Audio funkcióval rendelkező eseményrendszert.

Most rendeljen metódusokat a három gomb kattintási eseményeihez.

Miután minden be van állítva, futtassa a játékot, és próbálja meg játszani. Amikor a lejátszás véget ér, láthatja, hogy a dal közepétől hurkolódik és lejátssza. Természetesen ez feltételezi, hogy az audio adatok szépen el vannak osztva, és a hurkok szépen össze vannak kötve.

Az aktuális időtartam megjelenítése

Bónuszként innentől hozzáadtunk egy tulajdonságot, amely lehetővé teszi számunkra, hogy megkapjuk az aktuális lejátszási időt ,IntroLoopAudio ezért jelenítsük meg.

Először helyezze el a szöveget az idő megjelenítéséhez.

Hozzon létre egy szkriptet.

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

Csatoljon egy szkriptet a szöveghez, és állítsa be az EventSystem-et az IntroLoopAudio segítségével.

Futtassa, és nézze meg, hogy megjelenik-e az aktuális lejátszási idő. Hurok közben próbálja meg ellenőrizni, hogy az idő visszatér-e a hurokponthoz.