Зацикливайте фоновую музыку с вступлением

Страница обновлена :
Дата создания страницы :

Среда верификации

Виндоус
  • Windows 11
Редактор Unity
  • 2021.3.3f1
Входной системный пакет
  • 1.3.0

Предпосылки для этого совета

Следующие настройки были сделаны заранее в качестве предпосылки для описания этого совета.

О материале, входящем в состав образца

Фоновая музыка заимствована со следующего сайта.

Об аудиофайле цикла с интро

На этот раз только стандартная функция Unity будет воспроизводить цикл с вступлением, но это не поддерживается как стандартная функция. Во-первых, спецификации цикла с интро в виде аудиофайла не фиксированы, поэтому способ создания различается в зависимости от игрового фреймворка.

На этот раз мы подготовим два аудиофайла для части «вступления» и части «петли», сыграем вступительную часть один раз и многократно воспроизведем часть цикла. Поэтому, пожалуйста, подготовьте два вышеуказанных файла как аудиофайлы.

Некоторые сайты распространения учитывают это и заранее распространяют аудиофайлы отдельно. Если нет, вам нужно сделать это самостоятельно с помощью инструмента для редактирования голоса.

Если вы хотите разделить файл на две части, мы рекомендуем следующий формат аудиофайла.

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

Дополнительные сведения см. в официальной документации по Unity.

О воспроизведении зацикленной фоновой музыки с вступлением

Создайте пользовательский интерфейс, который позволяет воспроизводить, приостанавливать и останавливать фоновую музыку в качестве образца. Он имеет ту же компоновку, что и обычный образец воспроизведения фоновой музыки.

Добавьте в свой проект два аудиофайла, разделенных на две части: вступление и цикл.

На этот раз мы создадим нашу собственную программу для воспроизведения зацикленной фоновой музыки с вступлением. Создайте сценарий и оставьте его с именем IntroLoopAudio .

Скрипт выглядит следующим образом: Я имею в виду код на следующем сайте, но я добавил много кода, потому что он плохо работал с WebGL, и я хотел немного больше контроля.

[Справка] 【Единство】 Реализация 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;
  }
}

Так как код длинный, я опущу детали, но я заранее установил вступление и цикл AudioClip , Когда вы начнете играть, сначала сыграйте вступление. Для циклов запланируйте их воспроизведение, когда вступление закончится. Как только цикл начнет воспроизводиться, воспроизведите его несколько раз.

Изначально loop для циклов было достаточно установить true свойство в , но в WebGL оно не работало должным образом. AudioSource Я готовлю две петли и переключаю их поочередно, чтобы играть. Если вам не нужно рассматривать WebGL, вы можете сократить свой код вдвое.

После создания сценария его можно присоединить к объекту. Обычно лучше создать пустой объект и прикрепить его, но это хлопотно, поэтому присоедините его к EventSystem.

Есть вводные и циклические элементы, поэтому перетащите и установите аудиофайл соответственно.

На этом этапе никакой специальной обработки не требуется. Я хочу обработать его, когда нажимаю кнопку, поэтому я создаю сценарий (ButtonEvent) для кнопки.

Скрипт выглядит следующим образом:

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 из инспектора и добавить действия для каждой кнопки.

Сценарий прикрепляется к EventSystem. Поскольку вам нужно установить Intro Loop Audio, установите EventSystem, в которой есть Intro Loop Audio.

Теперь назначьте методы событиям нажатия трех кнопок.

Как только все настроено, запустите игру и попробуйте сыграть в нее. Когда воспроизведение заканчивается до конца, вы можете увидеть, что оно зацикливается с середины песни и воспроизводится. Конечно, это предполагает, что аудиоданные аккуратно разделены, а шлейфы аккуратно соединены.

Отображение текущей продолжительности

В качестве бонуса отсюда мы добавили свойство, которое позволяет нам получать текущее время воспроизведения в ,IntroLoopAudio поэтому давайте отобразим его.

Сначала поместите текст, чтобы отобразить время.

Создайте сценарий.

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

Прикрепите сценарий к тексту и установите EventSystem с помощью IntroLoopAudio.

Запустите его и посмотрите, отображается ли текущее время воспроизведения. Кроме того, при зацикливании попробуйте проверить, возвращается ли время в точку цикла.