控制同时播放的音效数量

更新页 :
页面创建日期 :

验证环境

窗户
  • 视窗 11
统一编辑器
  • 2021.3.3f1
输入系统包
  • 1.3.0

此提示的先决条件

作为此提示描述的前提,已预先进行了以下设置。

关于样品中包含的材料

音效是从以下网站借来的。

关于音频文件

可以使用 Unity 的标准功能播放以下音频文件格式: 请提前准备,因为它将在这些提示中使用。

  • 波浪 (.wav)
  • 奥格沃比斯 (.ogg)
  • MPEG 第 3 层 (.mp3)

有关更多信息,请参阅官方 Unity 文档。

关于多个同时播放音频的上限和音量

在前面的提示中, AudioClip 现在可以通过在 中准备 AudioSource.PlayOneShot 音频数据时播放多个语音来播放多个语音。 但是,可以玩的游戏数量没有限制,因此如果您在游戏过程中不限制它,可能会播放很多声音并且可能会播放很大的音量。

在这里,我想创建自己的程序并控制可以同时播放的音效数量。

创建示例

这一次,每次单击按钮时都会播放音效,因此请创建如图所示的 UI。 细节是适当和好的。

拖放要播放的音频文件并将其添加到项目中。

直到上次,标准功能 AudioSource 被添加到层次结构中, 这一次,我们将添加一个脚本,因为我们将放置自己的控件。 SoundPlayManager 将名称保留为 。

按如下方式创建脚本:

using System.Collections.Generic;
using UnityEngine;

/// <summary>音声再生管理クラスです。</summary>
public class SoundPlayManager : MonoBehaviour
{
  /// <summary>1つの種類の音声の再生情報を保持するクラスです。</summary>
  private class PlayInfo
  {
    /// <summary>再生している AudioSource の一覧です。</summary>
    public AudioSource[] AudioSource { get; set; }

    /// <summary>現在の再生インデックスです。</summary>
    public int NowIndex { get; set; }
  }

  /// <summary>再生しようとしている音声データのキューです。</summary>
  private HashSet<AudioClip> Queue = new HashSet<AudioClip>();

  /// <summary>再生している音声を管理している一覧です。</summary>
  private Dictionary<AudioClip, PlayInfo> Sources = new Dictionary<AudioClip, PlayInfo>();

  /// <summary>
  /// 同一音声同時再生最大数。
  /// </summary>
  [SerializeField, Range(1, 32)] private int MaxSimultaneousPlayCount = 2;

  protected void Update()
  {
    foreach (var item in Queue)
    {
      AudioSource source;
      if (Sources.ContainsKey(item) == false)
      {
        // 一度も再生されていない Clip がある場合は PlayInfo を生成します
        var info = new PlayInfo()
        {
          AudioSource = new AudioSource[MaxSimultaneousPlayCount],
        };
        for (int i = 0; i < MaxSimultaneousPlayCount; i++)
        {
          var s = gameObject.AddComponent<AudioSource>();
          s.clip = item;
          info.AudioSource[i] = s;
        }
        Sources.Add(item, info);
        source = info.AudioSource[0];
      }
      else
      {
        // 再生に使用する AudioSource を順番に取得します
        var info = Sources[item];
        info.NowIndex = (info.NowIndex + 1) % MaxSimultaneousPlayCount;
        source = info.AudioSource[info.NowIndex];
      }

      source.Play();
    }
    Queue.Clear();
  }

  /// <summary>
  /// 効果音を再生します。
  /// </summary>
  public void Play(AudioClip clip)
  {
    // 同一フレームで複数再生しないようにすでにキューに入っているか確認します
    if (Queue.Contains(clip) == false)
    {
      Queue.Add(clip);
    }
  }

  public void OnDestroy()
  {
    // 不要になった参照をすべて外します
    foreach (var source in Sources)
    {
      source.Value.AudioSource = null;
    }
    Sources.Clear();
    Queue.Clear();
  }
}

由于脚本较长,省略了详细说明,但它具有以下功能。

  • AudioClip 您可以通过传递播放音频
  • 当相同类型的音频相互叠加播放时,如果尝试播放超过一定数量的声音,则旧的播放数据将停止(初始值最多播放 2 次)。
  • 不允许在同一帧上重叠播放

这可以防止在背靠背播放相同音频时音量增加。 在功能方面,仅包含最低限度,因此如果需要,请添加它。

该脚本将附加到事件系统。

接下来,为按钮创建脚本。

按如下方式创建脚本:

using UnityEngine;

public class ButtonEvent : MonoBehaviour
{
  /// <summary>再生する音声データ。</summary>
  [SerializeField] private AudioClip AudioClip;

  /// <summary>自作した音声再生管理クラス。</summary>
  [SerializeField] private SoundPlayManager SoundPlayManager;

  /// <summary>ボタンをクリックしたとき。</summary>
  public void OnClick()
  {
    SoundPlayManager.Play(AudioClip);
  }
}

播放过程由自制 SoundPlayManager 自己完成,因此在按钮事件中,只需传递音频数据并播放即可。

该脚本将附加到事件系统。 附加管理不是本提示的主要主题,因此它是合适的。

对于音频剪辑,设置要播放的音频文件。 将声音播放管理器 SoundPlayManager 设置为要附加到的对象。 由于我们正在附加到事件系统,因此我们将设置事件系统。

最后,分配给 OnClick 按钮单击事件。

完成后运行游戏。 默认情况下,最大同时播放次数设置为 2,因此请在播放两个声音时再次单击该按钮,并确保第一个声音消失。

这次创建的程序对每种声音的播放次数有上限,因此即使您交织其他音效,听起来也很自然。 但是,根据声音的类型,2 的上限可能还不够,因此能够为每种声音类型设置上限可能是个好主意。 好吧,我不知道是否有这样的机会来分层声音,但是......