Loop baggrundsmusik med intro

Side opdateret :
Dato for oprettelse af side :

Miljø til bekræftelse

Windows
  • Windows 11
Enhedslistens redaktør
  • 2021.3.3f1
Input System Pakke
  • 1.3.0

Forudsætninger for dette tip

Følgende indstillinger er foretaget på forhånd som en forudsætning for beskrivelsen af dette tip.

Om det materiale, der følger med prøven

BGM lånes fra følgende side.

Om lydfilen i sløjfen med intro

Denne gang er det kun standard Unity-funktionen, der afspiller en løkke med en intro, men dette understøttes ikke som en standardfunktion. For det første er specifikationerne for sløjfen med intro som lydfil ikke fast, så oprettelsesmetoden varierer afhængigt af spilrammen.

Denne gang forbereder vi to lydfiler til "intro" -delen og "loop" -delen, spiller introdelen en gang og spiller loop-delen gentagne gange. Forbered derfor ovenstående to filer som lydfiler.

Nogle distributionssteder overvejer dette og distribuerer lydfiler separat på forhånd. Hvis ikke, skal du gøre det selv med et stemmeredigeringsværktøj.

Hvis du vil opdele filen i to, anbefaler vi følgende format af lydfilen.

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

Du kan finde flere oplysninger i den officielle Unity-dokumentation.

Om afspilning af looping baggrundsmusik med intro

Opret en brugergrænseflade, der giver dig mulighed for at afspille, pause og stoppe baggrundsmusik som et eksempel. Det har samme layout som en normal afspilningsprøve på baggrundsmusik.

Føj to lydfiler til dit projekt, opdelt i to dele, en introduktion og en løkke.

Denne gang opretter vi vores eget program til at spille looping BGM med introen. Opret et script, og lad det hedde IntroLoopAudio .

Scriptet ser sådan ud: Jeg henviser til koden på følgende websted, men jeg tilføjede en masse kode, fordi den ikke fungerede godt med WebGL, og jeg ønskede lidt mere kontrol.

[Henvisning] 【Enhed】 Implementer 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;
  }
}

Da koden er lang, vil jeg udelade detaljerne, men jeg indstiller intro og sløjfe AudioClip på forhånd, Når du begynder at spille, skal du først spille introen. For sløjfer skal du planlægge, at de skal spilles, når introen slutter. Når løkken begynder at spille, skal du afspille den gentagne gange.

Oprindeligt, for løkker, var det nok at indstille egenskaben true til , loop men det fungerede ikke korrekt i WebGL. AudioSource Jeg forbereder to sløjfer og skifter dem skiftevis for at spille. Hvis du ikke behøver at overveje WebGL, kan du halvere din kode.

Når du har oprettet et script, vedhæfter du det til et objekt. Normalt kan det være bedre at oprette et tomt objekt og vedhæfte det, men det er besværligt, så vedhæft det til EventSystem.

Der er intro- og loop-elementer, så slip og indstil henholdsvis lydfilen.

På dette tidspunkt kræves der ingen særlig behandling. Jeg vil behandle det, når jeg klikker på knappen, så jeg opretter et script (ButtonEvent) til knappen.

Scriptet ser sådan ud:

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 fra infovinduet, og tilføj handlinger for hver knap.

Scriptet er knyttet til EventSystem. Da du skal indstille Intro Loop Audio, skal du indstille det EventSystem, der har Intro Loop Audio.

Tildel nu metoder til klikhændelserne på de tre knapper.

Når alt er konfigureret, skal du køre spillet og prøve at spille det. Når afspilningen slutter til slutningen, kan du se, at den sløjfer fra midten af sangen og afspilles. Dette forudsætter selvfølgelig, at lyddataene er pænt opdelt, og sløjferne er forbundet pænt.

Få vist den aktuelle varighed

Som en bonus herfra har vi tilføjet en ejendom, der giver os mulighed for at få den aktuelle afspilningstid ind ,IntroLoopAudio så lad os vise det.

Placer først teksten for at vise klokkeslættet.

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

Vedhæft et script til teksten og indstil EventSystem med IntroLoopAudio.

Kør det og se om den aktuelle afspilningstid vises. Prøv også at kontrollere, om tiden vender tilbage til sløjfepunktet, når du sløjfer.