在本教程中,我将向你演示如何在 Unity 中播放一个音频文件,更重要的是,我会说明我是如何解决 Audio Source 音频重叠播放问题的。


本教程的视频版本目前尚未提供该语言版本。


视频文字稿

大家好。在本教程中,我将向你演示如何在 Unity 中播放一个音频文件,更重要的是,我会说明我是如何解决 Audio Source 音频重叠播放问题的。在继续之前请注意,视频中展示的解决方案只是我针对这个问题采用的一种方法,实际上可能还存在其他甚至更好的解决方案。因此,请不要将这里提供的信息视为唯一或最终的方法。

本教程使用的是 Unity 2022。具体来说,我希望当角色在场景中移动时播放脚步声音频文件。该音频来源于第一部《Prince of Persia》游戏,由 Jordan Mechner 制作,那是我第一次在 PC 上的游戏体验。这个任务看起来很简单,但正如我们将会看到的,其中隐藏着一个小问题。

要播放脚步声音频,第一步是为角色添加一个 Audio Source 对象。在这个对象中,我们将指定要播放的音频文件,并配置其他播放属性。

Audio Source 是一个需要添加到场景对象上的组件。这个对象可以是角色、一扇门、一个球体,甚至是一个不可见对象。不可见对象在某些情况下非常有用,例如当角色进入某个特定房间或靠近某个特定物体时播放音频。

为了让 Main Camera 能够听到声音,Camera 必须具有处于激活状态的 Audio Listener 组件。在新的 Unity 项目中,Main Camera 通常默认已经包含并启用了 Audio Listener 组件,因为系统假定用户希望能够听到音频。如果默认的 Audio Listener 缺失,可以通过 Main Camera 对象的 Inspector 面板手动添加。

在我的示例中,音频文件需要与角色关联。

在我的项目中,有一个 Player 对象,它是 Main Camera 的父对象。移动脚本关联在 Player 对象上,而 Camera 上则有一个用于实现视角旋转的脚本。因此,我会将 AudioSource 组件添加到 Player 对象上。

当打开新创建组件的选项卡时,你会立即看到 AudioClip 字段,初始状态为 None。

此外,还有一个名为 Play on Awake 的复选框,默认是选中的。该选项会在游戏开始时自动播放音频文件,在某些情况下很有用。但在当前示例中并不需要,因此我会取消勾选。

将音频文件导入项目非常简单。你只需将音频文件从 File Browser 窗口拖入 Project 面板,或者通过 Assets - Import New Asset 菜单从磁盘中选择导入。

Unity 支持多种音频格式,例如 mp3。导入后,在 Project 面板中你会看到对应资源旁边带有一个音符图标。

如你所见,我的项目中已经包含多个在不同场景中使用的音频文件。其中我们当前关注的文件名为 PoP---walk。

接下来,我首先在 Hierarchy 中选择 Player。

然后在 Project 面板中点击并按住 PoP---walk 资源。

最后,将该资源拖入 Player 上 AudioSource 组件的 AudioClip 框中。

正如之前所说,我们希望当角色移动时播放声音。

为此,我将打开负责角色移动的脚本,并插入所需代码。

首先,我创建一个 AudioSource 类型的变量,并在 Start 函数中将其与 Player 的 AudioSource 组件关联。

代码如下:

private AudioSource playerAudioSource;

在 Start 函数中写:

playerAudioSource = GetComponent();

我还需要创建一个 AudioClip 变量,用于关联需要播放的音频文件。我将其命名为 myAudioClip,并使用 SerializeField 属性,使其在 Inspector 面板中可见。

保存脚本后,下一步是在 Inspector 中将 PoP---Walk 资源拖入脚本中的 myAudioClip 字段。

在定义 playerAudioSource 之后,我写下以下代码:

[SerializeField] private AudioClip myAudioClip;

保存脚本后,回到 Unity 编辑器,并按照前面所述将 PoP---Walk 资源拖入脚本的 myAudioClip 字段。

此时,音频仍然不会播放。

在脚本的 Update 函数中,有一些用于检测用户按键输入的代码,用来控制角色移动。

当角色移动时,Input.GetAxis 的 Horizontal 和 Vertical 数值,我为了方便将其命名为 x 和 z,根据方向不同,其值可能为 -1 或 1。

在这种情况下,我可以写如下代码:

if ((Mathf.Abs(x) == 1) || (Mathf.Abs(z) == 1))

playerAudioSource.PlayOneShot(myAudioClip);

然后运行游戏。但这样做是一个严重的错误,因为 Unity 会在游戏的每一帧都播放一次音频文件。

即使我们将 PlayOneShot 放入 Coroutine 中,并添加一秒延迟命令 yield return new WaitForSeconds(1),问题依然存在。因为 Update 每一帧都会调用 Coroutine,最终还是会产生相同的错误。

因此,Coroutine 并不是必须的。我们真正需要做的是对 AudioSource 进行一个简单检查,只有当 AudioSource 当前没有播放时才播放音频。

可以在 Update 函数的 if 判断内部写下如下代码:

if (!(playerAudioSource.isPlaying))

playerAudioSource.PlayOneShot(myAudioClip);

现在我们可以保存脚本,运行游戏,并观察或者更准确地说是聆听结果。

在结束本教程之前,我想分享一个想法。AudioSource 组件中的 AudioClip 字段当然也可以通过脚本进行修改。

这意味着你可以使用同一个 AudioSource 播放标准脚步声音频,但在游戏过程中根据情况替换为其他音频文件。例如,当角色走在碎石地面、海岸线或其他表面时,可以通过 Colliders 进行识别并更换音频。

此外,如果角色可以飞行,你也可以禁用 AudioSource,从而不播放任何声音。

本教程到此结束,希望对你有所帮助。我们下次再见。

本网站仅用于展示我的部分作品,不具有任何推广或商业目的。请注意,目前我不接受,也不会回复任何定制项目、咨询服务或其他形式的合作请求。


高级隐私策略信息和cookie文件的使用