Hintergrundmusik mit Intro loopen

Diese Seite wurde aktualisiert :
Erstellungsdatum der Seite :

Verifizierungsumgebung

Fenster
  • Windows 11
Unity-Editor
  • 2021.3.3f1
Eingabesystem-Paket
  • 1.3.0

Voraussetzungen für diesen Tipp

Die folgenden Einstellungen wurden im Vorfeld als Prämisse für die Beschreibung dieses Tipps vorgenommen.

Über das Material, das in der Probe enthalten ist

Die Hintergrundmusik ist von der folgenden Website ausgeliehen.

Über die Audiodatei des Loops mit Intro

Dieses Mal spielt nur die Standard-Unity-Funktion eine Schleife mit einem Intro ab, dies wird jedoch nicht als Standardfunktion unterstützt. Erstens sind die Spezifikationen des Loops mit Intro als Audiodatei nicht festgelegt, sodass sich die Erstellungsmethode je nach Spielframework unterscheidet.

Dieses Mal bereiten wir zwei Audiodateien für den "Intro"-Teil und den "Loop"-Teil vor, spielen den Intro-Teil einmal und spielen den Loop-Teil wiederholt. Bitte bereiten Sie daher die beiden oben genannten Dateien als Audiodateien vor.

Einige Vertriebsseiten berücksichtigen dies und verteilen Audiodateien im Voraus separat. Wenn nicht, müssen Sie es mit einem Sprachbearbeitungstool selbst erstellen.

Wenn Sie die Datei in zwei Teile teilen möchten, empfehlen wir das folgende Format der Audiodatei.

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

Weitere Informationen finden Sie in der offiziellen Unity-Dokumentation.

Informationen zum Abspielen von Hintergrundmusik in Endlosschleife mit Intro

Erstellen Sie eine Benutzeroberfläche, mit der Sie Hintergrundmusik als Beispiel wiedergeben, anhalten und stoppen können. Es hat das gleiche Layout wie ein normales Sample für die Wiedergabe von Hintergrundmusik.

Fügen Sie Ihrem Projekt zwei Audiodateien hinzu, die in zwei Teile, ein Intro und einen Loop aufgeteilt sind.

Dieses Mal werden wir unser eigenes Programm erstellen, um die sich wiederholende Hintergrundmusik mit dem Intro abzuspielen. Erstellen Sie ein Skript und lassen Sie es IntroLoopAudio .

Das Skript sieht wie folgt aus: Ich beziehe mich auf den Code auf der folgenden Seite, aber ich habe viel Code hinzugefügt, weil er mit WebGL nicht gut funktionierte und ich etwas mehr Kontrolle wollte.

[Referenz] 【Einheit】 Intro + Loop-Wiedergabe implementieren - 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 der Code lang ist, werde ich die Details weglassen, aber ich stelle das Intro und die Schleife AudioClip im Voraus ein. Wenn Sie mit dem Spielen beginnen, spielen Sie zuerst das Intro ab. Planen Sie für Loops die Wiedergabe, wenn das Intro endet. Sobald die Schleife abgespielt wird, spielen Sie sie wiederholt ab.

Ursprünglich reichte es für Schleifen aus, loop die true Eigenschaft auf zu setzen, aber es funktionierte in WebGL nicht richtig. AudioSource Ich bereite zwei Loops vor und schalte sie abwechselnd zum Spielen. Wenn Sie WebGL nicht in Betracht ziehen müssen, können Sie Ihren Code halbieren.

Nachdem Sie ein Skript erstellt haben, hängen Sie es an ein Objekt an. Normalerweise kann es besser sein, ein leeres Objekt zu erstellen und es anzuhängen, aber es ist mühsam, also fügen Sie es an EventSystem an.

Es gibt Intro- und Loop-Elemente, also legen Sie die Audiodatei ab und stellen Sie sie ein.

An dieser Stelle ist keine spezielle Bearbeitung erforderlich. Ich möchte es verarbeiten, wenn ich auf die Schaltfläche klicke, also erstelle ich ein Skript (ButtonEvent) für die Schaltfläche.

Das Skript sieht wie folgt aus:

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 aus dem Inspektor und füge Aktionen für jede Taste hinzu.

Das Skript ist an EventSystem angehängt. Da Sie Intro-Loop-Audio festlegen müssen, legen Sie das EventSystem fest, das über Intro-Loop-Audio verfügt.

Weisen Sie nun den Klickereignissen der drei Schaltflächen Methoden zu.

Sobald alles eingerichtet ist, führen Sie das Spiel aus und versuchen Sie, es zu spielen. Wenn die Wiedergabe bis zum Ende endet, können Sie sehen, dass sie von der Mitte des Songs aus geloopt und abgespielt wird. Dies setzt natürlich voraus, dass die Audiodaten sauber aufgeteilt und die Loops sauber verbunden sind.

Anzeige der aktuellen Dauer

Als Bonus von hier aus haben wir eine Eigenschaft hinzugefügt, die es uns ermöglicht, die aktuelle Wiedergabezeit in zu erhalten,IntroLoopAudio also zeigen wir sie an.

Platzieren Sie zunächst den Text, um die Uhrzeit anzuzeigen.

Erstellen Sie ein 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}";
  }
}

Hängen Sie ein Skript an den Text an und stellen Sie das EventSystem mit IntroLoopAudio ein.

Führen Sie es aus und prüfen Sie, ob die aktuelle Wiedergabezeit angezeigt wird. Versuchen Sie beim Schleifen auch, zu überprüfen, ob die Zeit zum Schleifenpunkt zurückkehrt.