Putar musik latar belakang dengan intro

Halaman Diperbarui :
Tanggal pembuatan halaman :

Lingkungan verifikasi

Windows
  • jendela 11
Editor Kesatuan
  • 2021.3.3f1
Paket Sistem Input
  • 1.3.0

Prasyarat untuk tip ini

Pengaturan berikut telah dibuat sebelumnya sebagai premis untuk deskripsi tip ini.

Tentang materi yang disertakan dengan sampel

BGM dipinjam dari situs berikut.

Tentang file audio loop dengan intro

Kali ini, hanya fungsi Unity standar yang akan memainkan loop dengan intro, tetapi ini tidak didukung sebagai fungsi standar. Pertama-tama, spesifikasi loop dengan intro sebagai file audio tidak tetap, sehingga metode pembuatannya berbeda tergantung pada kerangka permainan.

Kali ini, kita akan menyiapkan dua file audio untuk bagian "intro" dan bagian "loop", memutar bagian intro sekali, dan memutar bagian loop berulang kali. Oleh karena itu, harap siapkan dua file di atas sebagai file audio.

Beberapa situs distribusi mempertimbangkan hal ini dan mendistribusikan file audio secara terpisah terlebih dahulu. Jika tidak, Anda harus membuatnya sendiri dengan alat pengeditan suara.

Jika Anda ingin membagi file menjadi dua, kami merekomendasikan format file audio berikut.

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

Untuk informasi selengkapnya, lihat dokumentasi resmi Unity.

Tentang memutar musik latar belakang berulang dengan intro

Buat UI yang memungkinkan Anda memutar, menjeda, dan menghentikan musik latar sebagai sampel. Ini memiliki tata letak yang sama dengan sampel pemutaran musik latar belakang normal.

Tambahkan dua file audio ke proyek Anda, pisahkan menjadi dua bagian, intro dan loop.

Kali ini, kita akan membuat program kita sendiri untuk memainkan BGM looping dengan intro. Buat skrip dan biarkan bernama IntroLoopAudio .

Skripnya terlihat seperti ini: Saya mengacu pada kode di situs berikut, tetapi saya menambahkan banyak kode karena tidak berfungsi dengan baik dengan WebGL dan saya ingin sedikit lebih banyak kontrol.

[Referensi] 【Persatuan】 Terapkan 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;
  }
}

Karena kodenya panjang, saya akan menghilangkan detailnya, tetapi saya mengatur intro dan loop AudioClip terlebih dahulu, Saat Anda mulai bermain, mainkan intro terlebih dahulu. Untuk loop, jadwalkan untuk diputar saat intro berakhir. Setelah loop mulai diputar, mainkan berulang kali.

Awalnya, untuk loop, itu cukup untuk mengatur true properti ke , loop tetapi tidak berfungsi dengan baik di WebGL. AudioSource Saya menyiapkan dua loop dan menggantinya secara bergantian untuk dimainkan. Jika Anda tidak perlu mempertimbangkan WebGL, Anda dapat memotong kode Anda menjadi dua.

Setelah Anda membuat skrip, Anda melampirkannya ke objek. Biasanya, mungkin lebih baik membuat objek kosong dan melampirkannya, tetapi merepotkan, jadi lampirkan ke EventSystem.

Ada item intro dan loop, jadi jatuhkan dan atur file audio masing-masing.

Pada titik ini, tidak diperlukan pemrosesan khusus. Saya ingin memprosesnya ketika saya mengklik tombol, jadi saya membuat skrip (ButtonEvent) untuk tombol tersebut.

Skripnya terlihat seperti ini:

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 dari inspektur dan tambahkan tindakan untuk setiap tombol.

Skrip dilampirkan ke EventSystem. Karena Anda perlu mengatur Audio Loop Intro, atur EventSystem yang memiliki Audio Loop Intro.

Sekarang tetapkan metode ke acara klik dari tiga tombol.

Setelah semuanya diatur, jalankan game dan coba mainkan. Ketika pemutaran berakhir sampai akhir, Anda dapat melihat bahwa itu loop dari tengah lagu dan diputar. Tentu saja, ini mengasumsikan bahwa data audio terbagi rapi dan loop terhubung dengan rapi.

Menampilkan durasi saat ini

Sebagai bonus dari sini, kami telah menambahkan properti yang memungkinkan kami mendapatkan waktu pemutaran saat ini di ,IntroLoopAudio jadi mari kita tampilkan.

Pertama, tempatkan teks untuk menampilkan waktu.

Buat skrip.

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

Lampirkan skrip ke teks dan atur EventSystem dengan IntroLoopAudio.

Jalankan dan lihat apakah waktu pemutaran saat ini ditampilkan. Juga, saat looping, cobalah untuk memeriksa apakah waktu kembali ke titik loop.