Unity游戏开发学习记录

Unity练习2 - 《John Lemon's Haunted

2023-12-27  本文已影响0人  我阿郑

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

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

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

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

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

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

✅ 【空间混合】设置

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

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

✅ 什么是非剧情音频?

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

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

✅ 创建音频源

image.png

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

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

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

✅ 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

尽管这是剧情声音,但仍应使用完全 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 游戏对象】。

✅ 更新 JohnLemon 预制件

image.png

✅ 将音频源添加到幽灵

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

➡️ 将音频添加到幽灵:

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

image.png

✅ 调整 3D Sound Settings 功能

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

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

image.png

✅ 纠正幽灵音效的方向

已经将 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) 预制件,返回到场景,保存场景。

游戏现在已完成!恭喜!

上一篇下一篇

猜你喜欢

热点阅读