这是用户在 2025-8-3 13:36 为 https://learn.unity.com/tutorial/yin-pin-b?uv=2020.3&projectId=5facf921edbc2a2003a58d3a# 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?
Unity Learn 主页
查看教程内容

音频

教程
初级
1 小时
(329)
摘要
到目前为止,游戏一直是没有声音的。在本教程中,你将了解如何使用音频文件播放一些背景音乐,或者在 Ruby 拾取生命值包或修复机器人时播放声音。
选择 Unity 版本
最后更新:2021 四月 12
2020.3
2020.2
2020.1
2019.4
2019.3
2019.2
2019.1
2018.4
2018.3
语言
中文

1.音频剪辑、音频源和音频监听器

Unity 声音系统包括:
1. 音频剪辑
与纹理或脚本一样,音频剪辑也是资源。你可以从音频文件(例如 mp3、ogg 和 wav 文件)导入音频剪辑,然后就会存放在 Project 文件夹中。你可以在 Audio 文件夹中找到本教程项目所需的音频剪辑
2.音频监听器
音频监听器是一个组件,可以定义“监听器”在场景中的位置。使用空间化声音时,此功能很有用。注:空间化声音是一种利用左/右扬声器(甚至在某些安装中使用前/后扬声器)上播放的声音,给玩家一种环绕声的感觉。
默认情况下,监听器位于摄像机上,因为玩家希望从摄像机的位置听到声音,所以屏幕右侧的声音应在右侧扬声器上播放。
如果在 Hierarchy 中单击 Camera,可以看到上面有一个 Audio Listener 组件。
3. 音频源
音频源 (Audio Source) 是一个组件,可以在该组件所在的游戏对象的位置播放音频剪辑。音频源的位置是相对于音频监听器的位置,这让音频系统可以混合声音,以便可以产生正确的空间感(如果我们使用空间化声音)。
即使不使用空间化声音,例如对于背景音乐,仍然可以在游戏对象上使用音频源,因为这样可以播放声音。

2.背景音乐

首先制作一些可以一直播放的背景音乐:
1.创建一个空的游戏对象,将其命名为 BackgroundMusic,并为其添加一个 Audio Source 组件:
选择要展开的图像
输入图像描述 (可选)

2.将项目的 Audio 文件夹中名为 2D MUSIC LOOP 的音频剪辑拖放到 AudioClip 属性字段中。
3.务必选中 Loop 选项,这样可以让音乐从头到尾不断循环播放。
4.然后检查 Spatial Blend 滑动条,该滑动条可以从 2D(左侧)滑动到 3D(右侧)。
此设置定义了声音是否空间化。如果滑动条完全在 2D 一侧,则声音不会被空间化,无论音频监听器在哪里,声音都将以相同的音量播放。
这有点像在音乐播放器中听音乐,并在音乐中设置了立体声。如果滑动条完全在 3D 一侧,则声音将在左右扬声器中以不同音量播放,具体取决于音频源相对于音频监听器的位置。
由于你的音乐需要在任何地方都听到相同的声音,因此请确保滑动条完全在 2D 一侧。目前暂时可以忽略其他属性。
提示:如果感到好奇,请单击组件右上角带有问号的书本图标以打开 Unity 手册
5.现在进入运行模式,你在游戏开始后应该会立即听到音乐开始播放。如果音量太大,可以随时用音量滑动条来尝试不同音量。
注意:切记,退出运行模式后,你在游戏运行过程中所做的任何更改都将被“撤销”,因此请确保记下要使用的值并在退出运行模式后调整设置。
6.如果在开发过程中由于任何原因需要使所有声音静音,请单击 Game 视图右上角的 Mute Audio 按钮。如果在应该听到声音时却听不到任何声音,可以看看是否启用了此按钮。
选择要展开的图像
输入图像描述 (可选)


3.一次性声音

如果需要一直播放声音,分配音频剪辑非常有用。但有些情况下,当发生某个事件时,例如当角色获得生命值可收集对象时,你需要播放一次性的声音。
一种选择是创建一个新的音频源,分配生命值可收集对象的音频剪辑,然后取消选中 Play On Awake 选项,这样在游戏开始时就不会播放音频。
然后,可以通过脚本设置当事件发生时播放音频剪辑。但这种做法需要为游戏中每个细小的声音都创建一个游戏对象音频源
你可以选择另一种做法,就是使用一个名为 PlayOneShot 的 AudioSource 函数。Play 用于播放分配给音频源的音频剪辑,与之不同的是,PlayOneShot 会将音频剪辑作为第一个参数,并在音频源的位置使用音频源的所有设置播放一次该音频剪辑。
因此,你可以将音频源添加到 Ruby 游戏对象,并使用该音频源播放与 Ruby 所做的游戏操作(比如拾取到生命值包、投掷齿轮或被击中)相关的所有声音。
注意:如果是在场景模式下而不是在预制件模式下将音频源添加到 Ruby,请在 Inspector 中应用覆盖!

4.向 Ruby 添加音频源后:

1. 打开你的 RubyController 脚本,添加一个名为 audioSource 的私有 AudioSource 变量来存储音频源,并使用 GetComponent 在 Start 函数中获取该变量。
2.然后,我们来编写一个名为 PlaySound 的函数,该函数将 AudioClip 作为参数,然后在 AudioSource 上直接调用 PlayOneShot
AudioSource audioSource; void Start() { rigidbody2d = GetComponent<Rigidbody2D>(); animator = GetComponent<Animator>(); currentHealth = maxHealth; audioSource= GetComponent<AudioSource>(); } public void PlaySound(AudioClip clip) { audioSource.PlayOneShot(clip); }
3.现在,打开 HealthCollectible 脚本,添加一个 AudioClip 类型的公共成员,命名为 collectedClip。然后在 RubyController 上调用 PlaySound 函数
public class HealthCollectible : MonoBehaviour { public AudioClip collectedClip; void OnTriggerEnter2D(Collider2D other) { RubyController controller = other.GetComponent<RubyController>(); if (controller != null) { if (controller.health < controller.maxHealth) { controller.ChangeHealth(1); Destroy(gameObject); controller.PlaySound(collectedClip); } } } }
为什么在 Ruby 上使用音频源,而不是在可收集对象上使用?很简单,因为音频源 (Audio Source) 是一个组件。当 Ruby 拾取了可收集对象后,这个可收集对象就被销毁了。这时也将销毁音频源并停止播放声音。
通过音频源在 Ruby 上播放声音,即使可收集对象被销毁,也可以播放声音。
4.现在,在 Project 窗口中检查你的生命值可收集对象预制件。现在,由于你已将相应变量设为公共变量,因此可以在 Health Collectible 组件上使用一个名为 Collected Clip 的新字段。将 Audio 文件夹中的 Collectable 音频剪辑拖放到该字段中。
5.现在,你可以进入运行模式,让 Ruby 拾取一个生命值包看看能不能听到声音,别忘了,你需要先让 Ruby 受到机器人的伤害以损失一些生命值!

5.练习

在此练习中,你可以尝试添加一个声音以便在 Ruby 投掷齿轮和/或她被敌人击中时播放。为此,你需要:
  • 就像我们在上面的 HealthCollectible 中所做的那样,将公共的 AudioClip 成员添加到 RubyController 脚本中以存储投掷声音或击中音频剪辑。
  • RubyController 脚本中的合适代码位置,在音频源上调用 PlayOneShot

6.空间化

到目前为止,你使用的都是 2D 声音。无论你距离音频源多远,播放的音量都一样。这在前面的内容中是合理的,因为这些声音是不属于世界的“游戏体验”声音(也称为故事外叙述/非剧情声音)。
但在许多交互式创作中,你希望声音存在于世界中,所以现在你要添加机器人走路的声音。
1.打开敌人机器人预制件,并向这个预制件添加一个音频源
2.将剪辑设置为 Audio 文件夹中名为 Robot Walking_Broken音频剪辑
3. 选中 Loop 设置。
4.最后,将 Spatial Blend 滑动条一直向右移动到 3D,以使该声音成为空间化声音。
Scene 视图中,你将在扬声器图标周围看到一个蓝色圆圈:
选择要展开的图像
输入图像描述 (可选)

这表示音频源的空间混合设置的最小距离。如果音频监听器位于该圆圈内,则可以听到最大音量的声音。然后,声音将缓慢衰减,直到达到最大距离为止,并在最大距离时静音。

7.什么是最大距离?

1. 你需要将 Scene 视图缩小很多才能看到:
选择要展开的图像
输入图像描述 (可选)

这个距离看起来太大,需要缩小。只要音频监听器在这个圆圈内,就会听到步行声音,但这个距离远大于当前的整个世界。
你可以拖动圆圈一侧的小点,但在 Inspector 中设置起来更容易。
2.在 Audio Source Inspector 的底部,打开 3D Sound Settings 部分便可找到 Min Distance Max Distance 设置:
选择要展开的图像
输入图像描述 (可选)

3.目前,我们的 Max Distance 设置为 500 个单位,非常大。我们现在改为 10 个单位。最大距离圆圈的大小现在应该更加符合实际了。
选择要展开的图像
输入图像描述 (可选)

超过这个圆圈的范围就不会听到声音。在这种设置中,如果监听器距离音频源的距离小于 1 个单位,则会以最大音量播放声音;如果距离 5 个单位,则会以一半的音量播放声音;如果距离音频源超过 10 个单位,则声音会静音,因为音量将为 0
4.现在保存预制件,然后回到场景
现在,如果你按 Play 并试玩游戏,你会发现衰减不起作用,并且听不到声音。这是因为声音系统是为 3D 设计的。所以该圆圈实际上是一个球体。
可以将 Scene 视图切换为 3D 模式来显示该球体。
选择要展开的图像
输入图像描述 (可选)

如以上截屏所示,摄像机位于整个游戏的略上方位置。因此,即使机器人位于屏幕中央,并且摄像机位于正上方,摄像机上的音频监听器仍处于与音频源之间的最大距离处,并且衰减最大!

8.修正衰减

1.要修正衰减,你需要将音频监听器放置在与其余游戏对象相同的深度,因此 z = 0
你不能更改摄像机,因为如果摄像机处于同一 z 位置,则会破坏渲染。
取而代之的做法是为摄像机创建一个子游戏对象。确保 z音频监听器协调。这样,音频监听器将随摄像机一起移动,始终在屏幕中央,但会根据 2D 距离正确计算衰减。
2.选择主摄像机并创建一个新的空游戏对象作为子对象。将这个对象命名为 Listener,向这个对象添加一个 Audio Listener,在 Transform 组件中将坐标设置为 x = 0y = 0z = 10
注意,此处设置的位置是相对于父对象的位置,因此会将子游戏对象放置在摄像机前方 10 个单位。
由于摄像机相对于平面后退 10 个单位,因此会将子游戏对象恰好放置在世界中的 z = 0 处。
3.摄像机上,右键单击 Audio Listener,然后选择 Remove Component
4.现在,你的设置已准备就绪,因此如果你进入运行模式,当机器人距离屏幕中心越来越远时,机器人的行走声音将被空间化(在左侧或右侧播放)并减弱。

9.检查你的脚本

你的 RubyController 脚本现在应如下所示:
public class RubyController : MonoBehaviour { public float speed = 3.0f; public int maxHealth = 5; public GameObject projectilePrefab; public AudioClip throwSound; public AudioClip hitSound; public int health { get { return currentHealth; }} int currentHealth; public float timeInvincible = 2.0f; bool isInvincible; float invincibleTimer; Rigidbody2D rigidbody2d; float horizontal; float vertical; Animator animator; Vector2 lookDirection = new Vector2(1,0); AudioSource audioSource; // 在第一次帧更新之前调用 Start void Start() { rigidbody2d = GetComponent<Rigidbody2D>(); animator = GetComponent<Animator>(); currentHealth = maxHealth; audioSource = GetComponent<AudioSource>(); } // 每帧调用一次 Update void Update() { horizontal = Input.GetAxis("Horizontal"); vertical = Input.GetAxis("Vertical"); Vector2 move = new Vector2(horizontal, vertical); if(!Mathf.Approximately(move.x, 0.0f) || !Mathf.Approximately(move.y, 0.0f)) { lookDirection.Set(move.x, move.y); lookDirection.Normalize(); } animator.SetFloat("Look X", lookDirection.x); animator.SetFloat("Look Y", lookDirection.y); animator.SetFloat("Speed", move.magnitude); if (isInvincible) { invincibleTimer -= Time.deltaTime; if (invincibleTimer < 0) isInvincible = false; } if(Input.GetKeyDown(KeyCode.C)) { Launch(); } if (Input.GetKeyDown(KeyCode.X)) { RaycastHit2D hit = Physics2D.Raycast(rigidbody2d.position + Vector2.up * 0.2f, lookDirection, 1.5f, LayerMask.GetMask("NPC")); if (hit.collider != null) { NonPlayerCharacter character = hit.collider.GetComponent<NonPlayerCharacter>(); if (character != null) { character.DisplayDialog(); } } } } void FixedUpdate() { Vector2 position = rigidbody2d.position; position.x = position.x + speed * horizontal * Time.deltaTime; position.y = position.y + speed * vertical * Time.deltaTime; rigidbody2d.MovePosition(position); } public void ChangeHealth(int amount) { if (amount < 0) { if (isInvincible) return; isInvincible = true; invincibleTimer = timeInvincible; PlaySound(hitSound); } currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth); UIHealthBar.instance.SetValue(currentHealth / (float)maxHealth); } void Launch() { GameObject projectileObject = Instantiate(projectilePrefab, rigidbody2d.position + Vector2.up * 0.5f, Quaternion.identity); Projectile projectile = projectileObject.GetComponent<Projectile>(); projectile.Launch(lookDirection, 300); animator.SetTrigger("Launch"); PlaySound(throwSound); } public void PlaySound(AudioClip clip) { audioSource.PlayOneShot(clip); } }
你的 HealthCollectible 脚本现在应如下所示:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class HealthCollectible : MonoBehaviour { public AudioClip collectedClip; void OnTriggerEnter2D(Collider2D other) { RubyController controller = other.GetComponent<RubyController>(); if (controller != null) { if (controller.health < controller.maxHealth) { controller.ChangeHealth(1); Destroy(gameObject); controller.PlaySound(collectedClip); } } } }

10.总结

在本教程中,你完成了交互式应用程序的最后一个主要部分:整合声音。
你了解了如何处理 2D 声音,无论角色在场景中的什么位置,这种声音都以相同的音量播放。你还学习了 3D 声音会根据声音与摄像机的相对位置以不同的音量和不同的扬声器播放。
下一教程将是最后一个教程!你现在已经完成游戏的每一部分,接下来需要了解下如何创建要分发给用户的应用程序,这样用户不必安装 Unity 就能玩你的游戏。

项目:
Ruby's Adventure:2D 初学者
音频
音频
一般教程讨论
0
0
1. 音频剪辑、音频源和音频监听器
0
0
2. 背景音乐
0
0
3. 一次性声音
5
4
4. 向 Ruby 添加音频源后:
5
2
5. 练习
3
4
6. 空间化
0
0
7. 什么是最大距离?
0
0
8. 修正衰减
0
1
9. 检查你的脚本
0
0
10. 总结
0
0