Unity练习2 - 《John Lemon's Haunted Jaunt》-7- 添加音频

本教程将使用两种不同的音频:

  • 非剧情声音,这种声音没有可识别的音源(比如音轨)
  • 剧情声音,这种声音具有可识别的音源(比如枪击声)

首先给游戏添加非剧情音频!

✅ 快速探究一下音频在 Unity 中的工作方式。

主要包括【三个部分】:音频剪辑 (Audio Clips)、音频源 (Audio Sources) 和音频监听器 (Audio Listener)。

  • 音频剪辑 (Audio Clips) 是诸如 MP3 之类的资源,其中包含与特定声音相关的所有数据

  • 音频源 (Audio Sources) 是在游戏世界中充当声音起源的组件。在游戏中发出声音的大多数事物都应具有音频源 (Audio Source) 组件,以便声音具有位置。

  • 音频监听器 (Audio Listener) 作为场景中的单个组件,其功能类似于玩家的虚拟耳朵(就像 Camera 组件的作用也类似于玩家的虚拟眼睛一样)。默认情况下,音频监听器 (Audio Listener) 组件位于主摄像机 (Main Camera) 上。

这些不同的部件通常以如下方式【协同工作】:音频源播放音频剪辑,如果音频监听器离音频源足够近,则可以听到声音

特定音频源的空间混合决定了音频听起来是来自游戏世界中的某个特定点,还是`无论音频源与音频监听器之间的距离如何都是同等大小的音量。

✅ 【空间混合】设置

空间混合设置为 2D 时,音频源和音频监听器之间的距离不会影响音量。(即,无论离特定物体远或近音量都是一样的)

空间混合设置为纯 3D,则音量将随着与音频监听器的距离不同而变化

✅ 什么是非剧情音频?

非剧情音频(没有可识别的音源的音频)可能会对您的游戏和玩家体验产生重大影响。

本游戏中添加三个非剧情声音:

  • 一个是循环播放的环境音轨,为鬼屋带来一般性的氛围
  • 一个是抓住 JohnLemon 时播放的音效
  • 一个是 JohnLemon 设法逃脱时播放的音效

✅ 创建音频源

  • Create Empty 命名为“Ambient”,Position为 (0, 0, 0)。
  • 给Ambient添加一个 Audio Source 组件
  • Assets > Audio 将 SFXHouseAmbience 音频剪辑拖到(AudioClip)。
  • Spatial Blend 设为 2D
  • 默认情况下还已经启用 Play On Awake。这意味着,一旦关卡开始,音频就会开始播放。
  • 启用 Loop 。
  • Volume 为 0.5
image.png

Ambient的Position在技术上并不重要,因为无论在哪里,音频的音量都是相同的。但是,为了防以后发生问题,让游戏对象的位置保持井然有序总是有用的。

接着,复制两个 Ambient ,第一个命名为“Escape”,将第二个命名为“Caught”。这两个声音不应立即播放,也不应循环,禁用 Play On Awake和Loop。此外,需要在游戏中的其他声音之外听到这些声音,因此它们应该比环境音频响亮,Volume 为 1。

  • Escape的AudioClip 为 SFXWin
  • Caught 的 AudioClip 为 SFXGameOver

到此,就已经设置好非剧情音频源。

✅ GameEnding 脚本中实现游戏结束音效

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameEnding : MonoBehaviour
{

    public float fadeDuration = 1f;  // 淡入淡出的默认值为1秒
    public float displayImageDuration = 1f;

    public GameObject player; // 玩家
    public CanvasGroup exitBackgroundImageCanvasGroup;
    // 此代码将为新图像创建另一个 CanvasGroup,如果抓住 JohnLemon,将显示这些图像。
    public CanvasGroup caughtBackgroundImageCanvasGroup;

    public AudioSource exitAudio;
    public AudioSource caughtAudio;

    bool m_IsPlayerAtExit;
    bool m_IsPlayerCaught; // 玩家是否被抓
    float m_Timer; // 需要一个计时器来确保游戏在淡入淡出之前不会结束
    bool m_HasAudioPlayed;// 需要创建一个变量以确保音频仅播放一次


    void OnTriggerEnter(Collider other)
    {// 监听触发器callback
        if (other.gameObject == player)
        {
            m_IsPlayerAtExit = true; // 发生触发
        }
    }

    public void CaughtPlayer()
    {
        m_IsPlayerCaught = true;
    }

    void Update()
    {
        if (m_IsPlayerAtExit)
        {
            EndLevel(exitBackgroundImageCanvasGroup,false, exitAudio);
        }
        else if (m_IsPlayerCaught)
        {
            EndLevel(caughtBackgroundImageCanvasGroup,true,caughtAudio);
        }
    }

    void EndLevel(CanvasGroup imageCanvasGroup, bool doRestart, AudioSource audioSource)
    {
        //确保音频仅播放一次
        if (!m_HasAudioPlayed)
        {
            audioSource.Play();
            m_HasAudioPlayed = true;
        }
        m_Timer += Time.deltaTime;

        imageCanvasGroup.alpha = m_Timer / fadeDuration;

        if (m_Timer > fadeDuration + displayImageDuration)
        {
            if (doRestart)
            {
                // 只有一个场景,因此索引为 0。
                SceneManager.LoadScene(0);
            }
            else
            {
                Application.Quit();
            }
        }
    }
}
image.png

这样,完成了非剧情音频的设置!

✅ 添加脚步声音频

现在,实现可以识别来源的音频。先从脚步声开始吧:

image.png
  • 选择 JohnLemon 游戏对象,添加 AudioSource 组件
  • AudioClip 设为 SFXFootstepsLooping
  • JohnLemon 在开始时处于静止状态,禁用 Play On Awake ,启用 Loop

尽管这是剧情声音,但仍应使用完全 2D 的空间混合 (Spatial Blend),以便音量不会随着 JohnLemon 的移动而变化,默认设置就很好。

✅ 返回到 PlayerMovement 脚本,播放音频

JohnLemon 走路时播放脚步声,而当他静止时停止播放脚步声。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    Animator m_Animator;
    Rigidbody m_Rigidbody;
    AudioSource m_AudioSource;
    // Unity 中表示矢量的数据类型称为 Vector3,游戏对象的位置便是由这种数据类型所表示
    Vector3 m_Movement;

    // 定义旋转速度
    // public的变量会出现在 Inspector 窗口中
    // 使用了 camelCase(而不是带有 m_ 前缀的 PascalCase)。
    // 这是因为该变量为公共变量,而 Unity 命名约定会对公共成员变量使用这种格式。
    public float turnSpeed = 40f;

    // 四元数 (Quaternion) 是存储旋转的一种方式,可用于解决将旋转存储为 3D 矢量时遇到的一些问题。
    // Quaternion.identity 就是为其赋予无旋转的值
    Quaternion m_Rotation = Quaternion.identity;

    void Start()
    {
        m_Animator = GetComponent<Animator>();
        m_Rigidbody = GetComponent<Rigidbody>();
        m_AudioSource = GetComponent<AudioSource>();
    }

    void FixedUpdate()
    {
        // Horizontal 的轴,由 A 和 D 键以及向左和向右键表示
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        // 设置角色移动位置
        // 该方法有三个参数,矢量的每个坐标对应一个参数。
        // 现在,移动矢量的值在 x 轴上为水平输入,在 y 轴上为 0,在 z 轴上为垂直输入。
        // 第二个参数的 0 后面还有一个 f,用于指示计算机将该数字视为浮点数。
        m_Movement.Set(horizontal, 0f, vertical);
        // 标准化
        m_Movement.Normalize();

        // 当 horizontal 为非零值时,hasHorizontalInput 为 true。
        bool hasHorizontalInput = !Mathf.Approximately(horizontal, 0f);
        bool hasVerticalInput = !Mathf.Approximately(vertical, 0f);
        bool isWalking = hasHorizontalInput || hasVerticalInput;
        m_Animator.SetBool("IsWalking", isWalking);

       
        if (isWalking)
        {
            if (!m_AudioSource.isPlaying)
            { // 走动时播放
                m_AudioSource.Play();
            }
        }
        else
        {
            m_AudioSource.Stop();
        }

        Vector3 desiredForward = Vector3.RotateTowards(transform.forward, m_Movement, turnSpeed * Time.deltaTime, 0f);
        m_Rotation = Quaternion.LookRotation(desiredForward);
    }

    void OnAnimatorMove()
    {
        //  移动
        m_Rigidbody.MovePosition(m_Rigidbody.position + m_Movement * m_Animator.deltaPosition.magnitude);
        // 旋转
        m_Rigidbody.MoveRotation(m_Rotation);
    }
}

✅ 将音频监听器 (Audio Listener) 移动到 JohnLemon

游戏的最后一段音频是幽灵在通过时发出的一些诡异声音。此音频不仅要营造气氛,还将帮助玩家识别危险离自己有多远

有一个难题是,幽灵的声音在幽灵靠近 JohnLemon 时不会变大,但在靠近摄像机时会变大。这是因为默认情况下,音频监听器 (Audio Listener) 位于主摄像机 (Main Camera) 上。第一步就是要更改此设置,【要将 Audio Listener 组件移到 JohnLemon 游戏对象】。

  • 选择 Main Camera 游戏对象 | 找到 Audio Listener 组件Remove 掉
  • 选择 JohnLemon 游戏对象| 添加 Audio Listener 组件

✅ 更新 JohnLemon 预制件

image.png

✅ 将音频源添加到幽灵

现在,JohnLemon 预制件具有音频监听器 (Audio Listener),所有幽灵音频都将具有相对于 JohnLemon 位置的音量。 这将使玩家更容易识别与幽灵之间的距离。

➡️ 将音频添加到幽灵:

选择 Ghost 游戏对象之一,添加Audio Source:

image.png
  • SFXGhostMove给AudioClip
  • 启用 Loop
  • Volume 为 0.4
  • 将 Spatial Blend 设置为 1,使其完全为 3D

✅ 调整 3D Sound Settings 功能

3D Sound Settings 用于控制音频如何随着与音频监听器 (Audio Listener) 之间的距离不同而变化。

调整几项高级功能,使幽灵具有出色的音效:

image.png
  • 将 Max Distance 改为 10。意味当幽灵在 10 米外时,玩家将可以非常轻微地听到它们的声音。
  • 音量随距离而变化的方式由 Volume Rolloff 控制。目前,此设置为 Logarithmic Rolloff,非常适合用于较远的距离。由于 Max Distance 现在仅为 10,请将 Volume Rolloff 更改为 Custom Rolloff
  • 默认的自定义曲线正好适合该游戏,因此无需调整此项。

✅ 纠正幽灵音效的方向

已经将 Audio Listener组件放在 JohnLemon 上,但有一个小问题:当 JohnLemon 转动时,音频监听器 (Audio Listener) 会也随之转动

这意味着 JohnLemon 面向屏幕时,玩家的虚拟眼睛(摄像机)和玩家的虚拟耳朵(音频监听器)将面向不同的方向。因此,听起来,鬼魂就像在对面。

使用两个属性,使幽灵的声音似乎毫无方向性,但随着幽灵的靠近,声音仍会变大:

  1. SFXGhostMove 音频剪辑已设置为播放单声道声音 (Mono) 而不是立体声 (Stereo)。这意味着通过左右声道的声音是相同的。(如果要查看 Import Settings,请在 Assets > Audio 中查找此部分,然后选择剪辑以查看其设置。)

2.在幽灵 (Ghost) 的 Audio Source 中找到 3D Sound Settings 的Spread 属性用于控制声音听起来的发生范围(以度为单位), 将 Spread 设为 180意味着一半的声音将来自每个声道,而由于这些声道相同,因此音频听起来将无方向性。

image.png

保存幽灵 (Ghost) 预制件,返回到场景,保存场景。

游戏现在已完成!恭喜!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容