Loop achtergrondmuziek met intro

Pagina bijgewerkt :
Aanmaakdatum van pagina :

Verificatieomgeving

Ramen
  • Voor Windows 11
Unity Editor
  • 2021.3.3f1
Input systeem pakket
  • 1.3.0

Vereisten voor deze tip

De volgende instellingen zijn vooraf gemaakt als uitgangspunt voor de beschrijving van deze tip.

Over het materiaal dat bij het monster is geleverd

BGM is geleend van de volgende site.

Over het audiobestand van de loop met intro

Deze keer zal alleen de standaard Unity-functie een lus met een intro spelen, maar dit wordt niet ondersteund als standaardfunctie. In de eerste plaats liggen de specificaties van de loop met intro als audiobestand niet vast, dus de creatiemethode verschilt afhankelijk van het spelkader.

Deze keer zullen we twee audiobestanden voorbereiden voor het "intro" -gedeelte en het "loop" -gedeelte, het introgedeelte één keer spelen en het loopgedeelte herhaaldelijk spelen. Bereid daarom de bovenstaande twee bestanden voor als audiobestanden.

Sommige distributiesites overwegen dit en distribueren audiobestanden vooraf afzonderlijk. Zo niet, dan moet je het zelf maken met een spraakbewerkingstool.

Als u het bestand in tweeën wilt splitsen, raden we u de volgende indeling van het audiobestand aan.

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

Zie voor meer informatie de officiële Unity-documentatie.

Over het spelen van looping achtergrondmuziek met intro

Maak een gebruikersinterface waarmee u achtergrondmuziek als voorbeeld kunt afspelen, pauzeren en stoppen. Het heeft dezelfde lay-out als een normaal voorbeeld voor het afspelen van achtergrondmuziek.

Voeg twee audiobestanden toe aan uw project, opgesplitst in twee delen, een intro en een lus.

Deze keer zullen we ons eigen programma maken om de looping BGM met de intro te spelen. Maak een script en laat het de naam IntroLoopAudio .

Het script ziet er als volgt uit: Ik verwijs naar de code op de volgende site, maar ik heb veel code toegevoegd omdat het niet goed werkte met WebGL en ik iets meer controle wilde.

[Referentie] 【Unity】Implementeer 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;
  }
}

Omdat de code lang is, zal ik de details weglaten, maar ik stel de intro en loop AudioClip van tevoren in, Wanneer je begint met spelen, speel je eerst de intro. Voor loops, plan ze om te spelen wanneer de intro eindigt. Zodra de lus begint te spelen, speel je deze herhaaldelijk af.

Oorspronkelijk was het voor lussen loop voldoende om de true eigenschap in te stellen op , maar het werkte niet goed in WebGL. AudioSource Ik bereid twee lussen voor en wissel ze afwisselend om te spelen. Als u WebGL niet hoeft te overwegen, kunt u uw code doormidden snijden.

Nadat u een script hebt gemaakt, koppelt u het aan een object. Normaal gesproken is het misschien beter om een leeg object te maken en het te koppelen, maar het is lastig, dus koppel het aan EventSystem.

Er zijn intro- en loop-items, dus laat het audiobestand respectievelijk vallen en instellen.

Op dit moment is er geen speciale verwerking vereist. Ik wil het verwerken wanneer ik op de knop klik, dus ik maak een script (ButtonEvent) voor de knop.

Het script ziet er als volgt uit:

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 vanuit het infovenster en voeg acties toe voor elke knop.

Het script is gekoppeld aan EventSystem. Aangezien u Intro Loop Audio moet instellen, stelt u het EventSystem in met Intro Loop Audio.

Wijs nu methoden toe aan de klikgebeurtenissen van de drie knoppen.

Zodra alles is ingesteld, voert u het spel uit en probeert u het te spelen. Wanneer het afspelen tot het einde eindigt, kunt u zien dat het vanuit het midden van het nummer wordt herhaald en wordt afgespeeld. Dit gaat er natuurlijk van uit dat de audiogegevens netjes verdeeld zijn en de lussen netjes met elkaar verbonden zijn.

De huidige duur weergeven

Als bonus van hierIntroLoopAudio hebben we een eigenschap toegevoegd waarmee we de huidige afspeeltijd kunnen krijgen , dus laten we deze weergeven.

Plaats eerst de tekst om de tijd weer te geven.

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

Voeg een script toe aan de tekst en stel het EventSystem in met IntroLoopAudio.

Voer het uit en kijk of de huidige afspeeltijd wordt weergegeven. Probeer ook bij het herhalen te controleren of de tijd terugkeert naar het luspunt.