Zančna glasba v ozadju z uvodom

Stran posodobljena :
Datum ustvarjanja strani :

Okolje za preverjanje

Windows
  • Windows 11
Urejevalnik Unity
  • 2021.3.3F1
Paket vhodnega sistema
  • 1.3.0

Predpogoji za ta nasvet

Naslednje nastavitve so bile vnaprej narejene kot premisa za opis tega nasveta.

O materialu, vključenem v vzorec

BGM si izposodimo na naslednji strani.

O zvočni datoteki zanke z uvodom

Tokrat bo zanko z uvodom igrala samo standardna funkcija Unity, vendar to ni podprto kot standardna funkcija. Prvič, specifikacije zanke z uvodom kot zvočno datoteko niso določene, zato se način ustvarjanja razlikuje glede na okvir igre.

Tokrat bomo pripravili dve zvočni datoteki za "uvodni" del in "zanko", enkrat odigrali uvodni del in večkrat odigrali zanko. Zato pripravite zgornji dve datoteki kot zvočne datoteke.

Nekatera distribucijska mesta to upoštevajo in vnaprej ločeno distribuirajo zvočne datoteke. Če ne, ga morate narediti sami z orodjem za urejanje glasu.

Če želite datoteko razdeliti na dva dela, priporočamo naslednjo obliko zvočne datoteke.

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

Za več informacij glejte uradno dokumentacijo Unity.

O predvajanju zankajoče glasbe v ozadju z uvodom

Ustvarite uporabniški vmesnik, s katerim lahko kot vzorec predvajate, začasno ustavite in ustavite glasbo v ozadju. Ima enako postavitev kot običajen vzorec predvajanja glasbe v ozadju.

V projekt dodajte dve zvočni datoteki, razdeljeni na dva dela, uvod in zanko.

Tokrat bomo ustvarili lasten program za igranje zančnega BGM z uvodom. Ustvarite skript in ga pustite poimenovati IntroLoopAudio .

Scenarij izgleda takole: Sklicujem se na kodo na naslednjem spletnem mestu, vendar sem dodal veliko kode, ker ni dobro delovala z WebGL in sem želel malo več nadzora.

[Sklic] 【Unity】Izvedite uvod + igranje zanke - 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;
  }
}

Ker je koda dolga, bom izpustil podrobnosti, vendar sem uvod in zanko AudioClip nastavil vnaprej, Ko začnete igrati, najprej predvajajte uvod. Za zanke jih razporedite tako, da se igrajo, ko se uvod konča. Ko se zanka začne predvajati, jo predvajajte večkrat.

Prvotno loop je bilo za zanke dovolj, da je bila lastnina nastavljena true na , vendar v WebGL ni delovala pravilno. AudioSource Pripravim dve zanki in ju izmenično preklopim na igro. Če vam ni treba upoštevati WebGL, lahko kodo razrežete na pol.

Ko ustvarite skript, ga priložite predmetu. Običajno je morda bolje ustvariti prazen predmet in ga priložiti, vendar je problematično, zato ga pritrdite na EventSystem.

Obstajajo elementi uvoda in zanke, zato spustite in nastavite zvočno datoteko.

Na tej točki ni potrebna posebna obdelava. Želim ga obdelati, ko kliknem gumb, zato ustvarim skript (ButtonEvent) za gumb.

Scenarij izgleda takole:

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 od inšpektorja in dodajte dejanja za vsak gumb.

Skript je priložen EventSystem. Ker morate nastaviti zvok Intro Loop, nastavite sistem dogodkov, ki ima zvok uvodne zanke.

Zdaj dodelite metode dogodkom klikov treh gumbov.

Ko je vse nastavljeno, zaženite igro in jo poskusite igrati. Ko se predvajanje konča do konca, lahko vidite, da se zanke od sredine pesmi in predvaja. Seveda to predpostavlja, da so zvočni podatki lepo razdeljeni in zanke lepo povezane.

Prikaz trenutnega trajanja

Kot bonus od tu smo dodali nepremičnino, ki nam omogoča, da dobimo trenutni čas predvajanja v ,IntroLoopAudio zato ga prikažimo.

Najprej postavite besedilo za prikaz časa.

Ustvarite skript.

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

Besedilu priložite skript in nastavite sistem dogodkov z IntroLoopAudio.

Zaženite ga in preverite, ali je prikazan trenutni čas predvajanja. Tudi pri ropanju poskusite preveriti, ali se čas vrne na točko zanke.