Cilpas fona mūzika ar ievadu

Lapa atjaunota :
Lapas izveides datums :

Verifikācijas vide

Windows
  • Operētājsistēmā Windows 11
Vienotības redaktors
  • 2021.3.3f1
Ievades sistēmas pakete
  • 1.3.0

Priekšnoteikumi šim padomam

Tālāk norādītie iestatījumi ir veikti iepriekš kā priekšnoteikums šī padoma aprakstam.

Par paraugā iekļauto materiālu

BGM tiek aizņemts no šīs vietnes.

Par cilpas audio failu ar ievadu

Šoreiz tikai standarta Unity funkcija spēlēs cilpu ar ievadu, taču tas netiek atbalstīts kā standarta funkcija. Pirmkārt, cilpas specifikācijas ar ievadu kā audio failu nav fiksētas, tāpēc izveides metode atšķiras atkarībā no spēles ietvara.

Šoreiz mēs sagatavosim divus audio failus "intro" daļai un "cilpas" daļai, vienreiz atskaņosim ievada daļu un atkārtoti atskaņosim cilpas daļu. Tāpēc, lūdzu, sagatavojiet iepriekš minētos divus failus kā audio failus.

Dažas izplatīšanas vietnes to apsver un iepriekš izplata audio failus atsevišķi. Ja nē, jums tas jādara pats, izmantojot balss rediģēšanas rīku.

Ja vēlaties sadalīt failu divās daļās, ieteicams izmantot šādu audio faila formātu.

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

Lai iegūtu papildinformāciju, skatiet oficiālo Unity dokumentāciju.

Par cilpas fona mūzikas atskaņošanu ar ievadu

Izveidojiet lietotāja interfeisu, kas ļauj atskaņot, pauzēt un apturēt fona mūziku kā paraugu. Tam ir tāds pats izkārtojums kā parastam fona mūzikas atskaņošanas paraugam.

Pievienojiet projektam divus audio failus, kas sadalīti divās daļās, ievadā un cilpā.

Šoreiz mēs izveidosim savu programmu, lai spēlētu cilpojošo BGM ar ievadu. Izveidojiet skriptu un atstājiet to ar nosaukumu IntroLoopAudio .

Skripts izskatās šādi: Es atsaucos uz kodu nākamajā vietnē, bet es pievienoju daudz koda, jo tas nedarbojās labi ar WebGL, un es gribēju nedaudz vairāk kontroles.

[Atsauce] 【Vienotība】Ieviest ievadu + cilpas spēli - 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;
  }
}

Tā kā kods ir garš, es izlaidīšu detaļas, bet ievadu un cilpu AudioClip iestatīju iepriekš, Kad sākat spēlēt, vispirms atskaņojiet ievadu. Cilpām ieplānojiet to spēlēšanu, kad beidzas ievads. Kad cilpa sāk spēlēt, spēlējiet to atkārtoti.

Sākotnēji loop cilpām pietika ar rekvizīta true iestatīšanu uz , bet WebGL tas nedarbojās pareizi. AudioSource Es sagatavoju divas cilpas un pārmaiņus pārslēdzu tās, lai spēlētu. Ja jums nav jāapsver WebGL, varat samazināt kodu uz pusēm.

Kad skripts ir izveidots, tas tiek pievienots objektam. Parasti var būt labāk izveidot tukšu objektu un pievienot to, bet tas ir apgrūtinoši, tāpēc pievienojiet to EventSystem.

Ir ievada un cilpas vienumi, tāpēc attiecīgi nometiet un iestatiet audio failu.

Šajā brīdī nav nepieciešama īpaša apstrāde. Es vēlos to apstrādāt, kad noklikšķinu uz pogas, tāpēc es izveidoju skriptu (ButtonEvent) pogai.

Skripts izskatās šādi:

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 no inspektora un pievienojiet darbības katrai pogai.

Skripts ir pievienots EventSystem. Tā kā jums ir jāiestata Intro Loop Audio, iestatiet notikumu sistēmu, kurai ir Intro Loop Audio.

Tagad piešķiriet metodes trīs pogu klikšķu notikumiem.

Kad viss ir iestatīts, palaidiet spēli un mēģiniet to spēlēt. Kad atskaņošana beidzas līdz beigām, jūs varat redzēt, ka tā cilpo no dziesmas vidus un tiek atskaņota. Protams, tas pieņem, ka audio dati ir kārtīgi sadalīti un cilpas ir savienotas kārtīgi.

Pašreizējā ilguma parādīšana

Kā bonusu no šejienes mēs esam pievienojuši īpašumu, kas ļauj mums iegūt pašreizējo atskaņošanas laiku ,IntroLoopAudio tāpēc parādīsim to.

Vispirms novietojiet tekstu, lai parādītu laiku.

Izveidojiet skriptu.

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

Pievienojiet tekstam skriptu un iestatiet EventSystem ar IntroLoopAudio.

Palaidiet to un pārbaudiet, vai tiek parādīts pašreizējais atskaņošanas laiks. Arī cilpas laikā mēģiniet pārbaudīt, vai laiks atgriežas cilpas punktā.