Enllaça la música de fons amb la introducció

Pàgina actualitzada :
Data de creació de la pàgina :

Entorn de verificació

Windows
  • Finestres 11
Editor d'unitat
  • 2021.3.3f1
Paquet del sistema d'entrada
  • 1.3.0

Requisits previs per a aquest consell

La configuració següent s'ha fet amb antelació com a premissa per a la descripció d'aquest consell.

Sobre el material inclòs en la mostra

BGM es pren prestat del següent lloc.

Quant al fitxer d'àudio del bucle amb introducció

Aquesta vegada, només la funció Unity estàndard reproduirà un bucle amb una introducció, però això no s'admet com a funció estàndard. En primer lloc, les especificacions del bucle amb introducció com a fitxer d'àudio no es fixen, de manera que el mètode de creació difereix en funció del marc del joc.

Aquesta vegada, prepararem dos fitxers d'àudio per a la part "intro" i la part "bucle", reproduirem la part d'introducció una vegada i reproduirem la part del bucle repetidament. Per tant, prepareu els dos fitxers anteriors com a fitxers d'àudio.

Alguns llocs de distribució ho consideren i distribueixen fitxers d'àudio per separat per endavant. Si no, heu de fer-ho vosaltres mateixos amb una eina d'edició de veu.

Si voleu dividir el fitxer en dos, us recomanem el següent format del fitxer d'àudio.

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

Per obtenir més informació, consulteu la documentació oficial de la Unitat.

Sobre la reproducció de música de fons en bucle amb la introducció

Creeu una interfície d'usuari que us permeti reproduir, posar en pausa i aturar música de fons com a mostra. Té el mateix disseny que una mostra normal de reproducció de música de fons.

Afegiu dos fitxers d'àudio al vostre projecte, dividits en dues parts, una introducció i un bucle.

Aquesta vegada, crearem el nostre propi programa per reproduir el bucle BGM amb la introducció. Creeu un script i deixeu-lo anomenat IntroLoopAudio .

El guió té aquest aspecte: Em refereixo al codi del lloc següent, però he afegit molt codi perquè no funcionava bé amb WebGL i volia una mica més de control.

[Referència] 【Unity】Implementa la introducció + 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;
  }
}

Com que el codi és llarg, ometo els detalls, però estableixo la introducció i el bucle AudioClip per endavant, Quan comenceu a reproduir, reproduïu primer la introducció. Per als bucles, programeu-los perquè es reprodueixin quan finalitzi la introducció. Un cop el bucle comenci a sonar, toqueu-lo repetidament.

Originalment, per als bucles, n'hi havia prou amb establir la true propietat a , loop però no funcionava correctament a WebGL. AudioSource Preparo dos bucles i els canvio alternativament per jugar. Si no heu de tenir en compte WebGL, podeu tallar el codi per la meitat.

Després de crear un script, l'adjuntes a un objecte. Normalment, pot ser millor crear un objecte buit i adjuntar-lo, però és problemàtic, així que adjunteu-lo a EventSystem.

Hi ha elements d'introducció i bucle, de manera que deixeu anar i configureu el fitxer d'àudio respectivament.

En aquest punt, no es requereix cap tractament especial. Vull processar-lo quan faig clic al botó, així que creo un script (ButtonEvent) per al botó.

El guió té aquest aspecte:

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 de l'inspector i afegiu accions per a cada botó.

L'script s'adjunta a EventSystem. Com que heu d'establir Intro Loop Audio, configureu el sistema d'esdeveniments que té Intro Loop Audio.

Ara assigneu mètodes als esdeveniments de clic dels tres botons.

Un cop tot configurat, executeu el joc i proveu de jugar-hi. Quan la reproducció acaba fins al final, podeu veure que es reprodueix en bucle des del centre de la cançó i es reprodueix. Per descomptat, això suposa que les dades d'àudio estan perfectament dividides i els bucles estan connectats perfectament.

Mostra la durada actual

Com a bonificació a partir d'aquí, hem afegit una propietat que ens permet obtenir el temps de reproducció actual a ,IntroLoopAudio així que mostrem-lo.

Primer, col·loqueu el text per mostrar l'hora.

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

Adjunteu un script al text i configureu l'EventSystem amb IntroLoopAudio.

Executeu-lo i comproveu si es mostra l'hora de reproducció actual. A més, quan feu un bucle, intenteu comprovar si l'hora torna al punt del bucle.