Silmukka taustamusiikkia intron avulla

Sivu päivitetty :
Sivun luontipäivämäärä :

Varmennusympäristö

Windows
  • Windows 11
Unity-editori
  • 2021.3.3F1
Syöttöjärjestelmän paketti
  • 1.3.0

Tämän vinkin edellytykset

Seuraavat asetukset on tehty etukäteen tämän vinkin kuvauksen lähtökohtana.

Tietoja näytteeseen sisältyvästä materiaalista

BGM on lainattu seuraavalta sivustolta.

Tietoja silmukan äänitiedostosta, jossa on intro

Tällä kertaa vain tavallinen Unity-toiminto toistaa silmukan intron kanssa, mutta tätä ei tueta vakiotoimintona. Ensinnäkin silmukan tekniset tiedot, joissa on intro äänitiedostona, eivät ole kiinteitä, joten luomismenetelmä vaihtelee pelikehyksen mukaan.

Tällä kertaa valmistelemme kaksi äänitiedostoa "intro" -osaan ja "loop" -osaan, soitamme intro-osan kerran ja toistamme silmukkaosan toistuvasti. Siksi valmistele yllä olevat kaksi tiedostoa äänitiedostoiksi.

Jotkut jakelusivustot harkitsevat tätä ja jakavat äänitiedostoja erikseen etukäteen. Jos ei, sinun on tehtävä se itse äänenmuokkaustyökalulla.

Jos haluat jakaa tiedoston kahtia, suosittelemme äänitiedoston seuraavaa muotoa.

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

Lisätietoja on virallisissa Unity-dokumentaatiossa.

Tietoja silmukoivan taustamusiikin toistamisesta intron avulla

Luo käyttöliittymä, jonka avulla voit toistaa, keskeyttää ja pysäyttää taustamusiikkia näytteenä. Sillä on sama asettelu kuin tavallisella taustamusiikin toistonäytteellä.

Lisää projektiisi kaksi äänitiedostoa, jotka on jaettu kahteen osaan, esittelyyn ja silmukkaan.

Tällä kertaa luomme oman ohjelman silmukan BGM: n soittamiseksi intron kanssa. Luo komentosarja ja jätä sen nimeksi IntroLoopAudio .

Skripti näyttää tältä: Viittaan seuraavan sivuston koodiin, mutta lisäsin paljon koodia, koska se ei toiminut hyvin WebGL: n kanssa ja halusin hieman enemmän hallintaa.

[Viite] 【Unity】 Toteuta 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;
  }
}

Koska koodi on pitkä, jätän yksityiskohdat pois, mutta asetin intron ja silmukan AudioClip etukäteen, Kun aloitat pelaamisen, toista ensin esittely. Jos kyseessä on silmukka, ajoita ne toistettaviksi, kun intro päättyy. Kun silmukka alkaa toistua, toista sitä toistuvasti.

Alun perin loop silmukoille riitti, että ominaisuudeksi true asetettiin , mutta se ei toiminut oikein WebGL: ssä. AudioSource Valmistelen kaksi silmukkaa ja vaihdan ne vuorotellen soittaakseni. Jos sinun ei tarvitse harkita WebGL: ää, voit leikata koodisi puoleen.

Kun olet luonut komentosarjan, liität sen objektiin. Normaalisti voi olla parempi luoda tyhjä objekti ja liittää se, mutta se on hankala, joten liitä se EventSystemiin.

On esittely- ja silmukkakohteita, joten pudota ja aseta äänitiedosto vastaavasti.

Tässä vaiheessa erityistä käsittelyä ei tarvita. Haluan käsitellä sen, kun napsautan painiketta, joten luon komentosarjan (ButtonEvent) painikkeelle.

Skripti näyttää tältä:

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 inspektorista ja lisää toimintoja jokaiselle painikkeelle.

Skripti on liitetty EventSystemiin. Koska sinun on asetettava Intro Loop Audio, aseta EventSystem, jossa on Intro Loop Audio.

Määritä nyt menetelmät kolmen painikkeen napsautustapahtumille.

Kun kaikki on määritetty, suorita peli ja yritä pelata sitä. Kun toisto päättyy loppuun, näet, että se silmukoituu kappaleen keskeltä ja soi. Tämä tietysti olettaa, että äänidata on jaettu siististi ja silmukat on kytketty siististi.

Näytä nykyinen kesto

Bonuksena täältä olemme lisänneet ominaisuuden, jonka avulla voimme saada nykyisen toistoajan ,IntroLoopAudio joten näytetään se.

Aseta ensin teksti näyttämään aika.

Luo komentosarja.

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

Liitä tekstiin skripti ja aseta EventSystem IntroLoopAudiolla.

Suorita se ja katso, näkyykö nykyinen toistoaika. Kun silmukkaa, yritä myös tarkistaa, palaako aika silmukkapisteeseen.