Loop μουσική υπόκρουση με εισαγωγή

Σελίδα ενημέρωση :
Ημερομηνία δημιουργίας σελίδας :

Περιβάλλον επαλήθευσης

παράθυρα
  • Παράθυρα 11
Επεξεργαστής ενότητας
  • 2021.3.3στ1
Πακέτο συστήματος εισόδου
  • 1.3.0

Προϋποθέσεις για αυτήν τη συμβουλή

Οι ακόλουθες ρυθμίσεις έχουν γίνει εκ των προτέρων ως προϋπόθεση για την περιγραφή αυτής της συμβουλής.

Σχετικά με το υλικό που περιλαμβάνεται στο δείγμα

Το BGM δανείζεται από τον ακόλουθο ιστότοπο.

Σχετικά με το αρχείο ήχου του βρόχου με εισαγωγή

Αυτή τη φορά, μόνο η τυπική συνάρτηση Unity θα αναπαράγει βρόχο με εισαγωγή, αλλά αυτό δεν υποστηρίζεται ως τυπική συνάρτηση. Πρώτον, οι προδιαγραφές του βρόχου με εισαγωγή ως αρχείο ήχου δεν είναι σταθερές, επομένως η μέθοδος δημιουργίας διαφέρει ανάλογα με το πλαίσιο του παιχνιδιού.

Αυτή τη φορά, θα ετοιμάσουμε δύο αρχεία ήχου για το μέρος "εισαγωγή" και το μέρος "βρόχος", θα παίξουμε το εισαγωγικό μέρος μία φορά και θα παίξουμε επανειλημμένα το μέρος βρόχου. Επομένως, προετοιμάστε τα παραπάνω δύο αρχεία ως αρχεία ήχου.

Ορισμένοι ιστότοποι διανομής το θεωρούν αυτό και διανέμουν αρχεία ήχου ξεχωριστά εκ των προτέρων. Εάν όχι, πρέπει να το κάνετε μόνοι σας με ένα εργαλείο επεξεργασίας φωνής.

Εάν θέλετε να χωρίσετε το αρχείο στα δύο, συνιστούμε την ακόλουθη μορφή του αρχείου ήχου.

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

Για περισσότερες πληροφορίες, ανατρέξτε στην επίσημη τεκμηρίωση του Unity.

Πληροφορίες για την αναπαραγωγή επαναλαμβανόμενης μουσικής υπόκρουσης με εισαγωγή

Δημιουργήστε ένα περιβάλλον εργασίας χρήστη που σας επιτρέπει να κάνετε αναπαραγωγή, παύση και διακοπή της μουσικής υπόκρουσης ως δείγμα. Έχει την ίδια διάταξη με ένα κανονικό δείγμα αναπαραγωγής μουσικής υπόκρουσης.

Προσθέστε δύο αρχεία ήχου στο έργο σας, χωρισμένα σε δύο μέρη, μια εισαγωγή και έναν βρόχο.

Αυτή τη φορά, θα δημιουργήσουμε το δικό μας πρόγραμμα για να παίξουμε το looping BGM με την εισαγωγή. Δημιουργήστε ένα σενάριο και αφήστε το με το όνομα IntroLoopAudio .

Το σενάριο μοιάζει με αυτό: Αναφέρομαι στον κώδικα στον παρακάτω ιστότοπο, αλλά πρόσθεσα πολύ κώδικα επειδή δεν λειτούργησε καλά με το WebGL και ήθελα λίγο περισσότερο έλεγχο.

[Παραπομπή] 【Unity】Εφαρμογή 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 εκ των προτέρων, Όταν αρχίσετε να παίζετε, παίξτε πρώτα την εισαγωγή. Για βρόχους, προγραμματίστε τους να παίζουν όταν τελειώσει η εισαγωγή. Μόλις αρχίσει να παίζει ο βρόχος, παίξτε τον επανειλημμένα.

Αρχικά, για βρόχους, ήταν αρκετό να ορίσετε την true ιδιότητα σε , loop αλλά δεν λειτούργησε σωστά στο 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.

Εκτελέστε το και δείτε εάν εμφανίζεται ο τρέχων χρόνος αναπαραγωγής. Επίσης, κατά την επανάληψη, προσπαθήστε να ελέγξετε εάν ο χρόνος επιστρέφει στο σημείο βρόχου.