Skip to content

Files

Latest commit

5f0ab0e · Dec 25, 2021

History

History
484 lines (355 loc) · 47 KB

File metadata and controls

484 lines (355 loc) · 47 KB

八、特效——声音和粒子

在前一章中,我们从猴球游戏中短暂休息,了解了 Unity 中的物理和 2D 游戏。我们创造了愤怒的小鸟的克隆体。这些鸟利用物理原理在空中飞行,摧毁猪和它们的结构。我们利用视差滚动来制造令人愉悦的背景效果。我们还创建了一个关卡选择屏幕,您可以从中加载游戏的各种场景。

在这一章,我们回到猴子球游戏。我们将增加许多特效,丰富游戏体验。我们将从了解 Unity 在处理音频时提供的控制开始。然后,我们将继续为游戏添加一些背景音乐,并为我们的猴子添加运动声音。接下来,我们将学习粒子系统,为猴子创造一个尘埃轨迹。最后,我们结合本章中解释的效果,为用户收集香蕉时创建爆炸。

在本章中,我们将涵盖以下重要主题:

  • 导入音频剪辑
  • 玩 SFX
  • 了解 2D 和 3D SFX
  • 创建粒子系统

打开你的猴球项目,让我们开始吧。

理解音频

与其他素材一样,Unity 团队已经努力工作,使音频工作变得简单和无障碍。Unity 能够导入和利用多种音频格式,允许您将文件保存为可以在其他程序中编辑的格式。

导入设置

音频剪辑有一小部分重要设置。它们可以让您轻松控制文件的类型和压缩。下面的截图显示了我们在导入音频剪辑时必须使用的设置:

Import settings

前面截图中的选项如下:

  • 强制为单声道:此复选框将导致 Unity 将多声道文件更改为具有单声道音频数据。
  • 后台加载:这会导致一个音频文件的初始加载不会暂停整个游戏,而它正在将游戏加载到内存中。对于不需要立即使用的大型文件,最好使用这种方法。
  • 预加载音频数据:这将导致音频信息被尽快加载。这最适合需要立即使用的小文件。
  • 加载类型:控制游戏进行中文件如何加载;您可以从以下三个可用选项中进行选择:
    • 加载时解压缩:这将在文件第一次需要时移除压缩。这个选项的开销使得它对于大文件来说是一个非常糟糕的选择。此选项最适合您经常听到的短声音,例如射击游戏中的枪声。
    • 内存压缩:这只是在文件播放时进行解压缩。当它刚刚被保存在内存中时,文件保持压缩状态。对于不常听到的中短音来说,这是一个不错的选择。
    • 流式传输:这将在音频播放时加载音频,例如从网络上流式传输音乐或视频。此选项最适合背景音乐等内容。
  • 压缩格式:这允许您选择用于减小音频文件大小的压缩格式。 PCM 格式将为您提供最大的文件大小和最佳的音频质量。 Vorbis 格式可以给你最小的文件大小,但是越小质量越差。 ADPCM 格式适应音频文件的布局,以便给你一个中间的文件大小。
  • 质量:仅当选择 Vorbis 作为压缩格式时使用。较低的值会减小项目中文件的最终大小,但也会给音频带来越来越多的失真。
  • 采样率设置:这可以让你决定在 Unity 中保留多少音频文件的细节。保留采样速率选项将保持原始文件中使用的设置。优化采样率选项将允许 Unity 选择适合您文件的设置。覆盖采样率选项将允许您访问采样率的值,并为您的音频选择特定的设置。较小的值将减小整个文件的大小,代价是降低质量。

音频监听器

为了在游戏中真正听到任何东西,每个场景都需要一个音频监听器组件。默认情况下,Main Camera对象(首先包含在任何新场景中)和您可能创建的任何新相机都附加了一个音频监听器组件。您的场景中一次只能有一个 音频监听器组件。如果有多个组件,或者您试图在没有组件时播放声音,Unity 会在您的控制台日志中填入投诉和警告。音频监听器组件还提供了关闭任何 3D 音效的精确位置。

音频源

音源组件就像一个扬声器,它控制着用来播放任何音效的设置。如果片段是 3D 的,则该对象相对于音频监听器组件的位置和所选模式决定了片段的音量。下面的截图显示了一个音源组件的各种设置,以及它们的解释:

Audio Source

  • 音频剪辑:默认情况下,这是这个音频源组件将要播放的声音文件。

  • 输出:对于复杂的音效,这里可以放一个 Unity 新的混音器对象。这些功能允许您在最终播放音频之前,对音频以及可能应用于音频的任何效果或混合进行特定控制。

  • 静音:这是一种快速切换正在播放的声音音量的方法。

  • 旁路效果:这允许您切换应用于音频源组件的任何特殊滤镜。

  • 绕过监听器效果:这允许音频忽略任何可能应用于音频监听器的特殊效果。这是一个背景音乐的好设置,不应该被世界扭曲。

  • 绕过混响区:这允许您控制控制环境音频中过渡区域的混响区是否影响声音。

  • 清醒时播放:这将导致当场景加载或对象产生时,音频剪辑立即开始播放。

  • 循环:此将导致播放片段在播放时重复播放。

  • 优先级:这决定了正在播放的文件的相对重要性。值0表示音乐最重要最好的,而256表示最不重要的文件。根据系统的不同,一次只能播放这么多声音。要播放的文件列表从最重要的开始,并在达到此限制时结束,如果声音超过限制允许的数量,则排除那些具有最低值的文件。

  • 音量:这决定了剪辑的播放音量。

  • 音高:这可以缩放片段的播放速度。

  • 立体声声相:这将调整声音从每个扬声器中发出的均匀程度,并向左侧或右侧扬声器加权。

  • 空间混合:这是要应用于音频源组件的 3D 效果的百分比。这会影响衰减和多普勒效应。

  • Reverb Zone Mix: (Reverb zones are used to create transitions in ambient audio effects.) This setting lets you adjust how much effect these zones will have on the audio from this audio source.

    Audio Source

上图设置如下:

  • 3D 声音设置:包含一组特定于 3D 音频剪辑播放的设置。音量空间扩散混响选项可以使用组末的图表进行调整。这允许您在播放器接近音频源组件时创建更多动态过渡:
    • 多普勒水平:这决定了需要对运动的声音施加多大的多普勒效应。多普勒效应是当声源靠近或远离你时所经历的音调变化。一个典型的例子是一辆汽车飞驰而过时,喇叭响了起来。
    • 音量衰减:这控制音量如何随距离衰减。有三种类型的滚降:
      • 对数衰减:这是声音在距离声源中心很短的距离内突然快速衰减。
      • 线性衰减:这是一个随距离的均匀衰减,在最小距离值处最大,在最大距离值处最安静。
      • 自定义衰减:这允许您通过调整群组末端的图形来创建自定义衰减。当图形改变时,也会自动选择它。
    • 如果音频监听器组件比最小距离值更近,则音频将以当前音量播放。在这个距离之外,声音会按照滚降模式下降。
    • 扩散:这将调整声音覆盖的扬声器空间面积。当使用一个或两个以上的扬声器时,这变得更加重要。
    • 超过最大距离值后,根据群组底部的图表,声音将停止转换。

添加背景音乐

现在我们已经知道了可用的音频设置,是时候将这些知识付诸行动了。我们将从添加一些背景音乐开始。无论音源组件在哪里,这都必须是 2D 音效,这样我们才能舒适地听到。我们还将创建一个简短的脚本来淡入音乐,以减少音效轰炸播放器的突然性。我们将使用以下步骤来做到这一点:

  1. 我们将从创建一个新的脚本开始,并将其命名为FadeIn

  2. 这个脚本从四个变量开始。第一个变量是脚本必须达到的目标量。第二个是转换将花费的秒数。第三个变量是过渡开始的时间。最后一个变量跟踪与我们的脚本附加到同一对象的音频源组件,允许我们定期更新它,如下所示:

    public float maxVolume = 1f;
    public float fadeLength = 1f;
    private float fadeStartTime = -1f;
    private AudioSource source;
  3. 接下来,我们利用Awake功能。它开始于检查附加的音源组件,并用它填充我们的source变量。如果找不到,则游戏对象被破坏,并退出功能:

    public void Awake() {
      source = gameObject.GetComponent<AudioSource>();
      if(source == null) {
        Destroy(gameObject);
        return;
      }
  4. Awake功能通过将音频音量设置为0结束,如果尚未播放,则开始播放:

    source.volume = 0;
    
    if(!source.isPlaying)
      source.Play();
    }
  5. 为了引起随时间的转变,我们使用Update函数。它将检查fadeStartTime变量的值是否低于零,如果是,则将它设置为当前时间。这使您可以避免可能由场景开始初始化引起的打嗝:

    public void Update() {
      if(fadeStartTime < 0)
        fadeStartTime = Time.time;
  6. 接下来,该函数检查转换时间是否已经结束。如果有,音源组件的音量设置为maxVolume,为了释放资源,脚本被销毁:

    if(fadeStartTime + fadeLength < Time.time) {
      source.volume = maxVolume;
      Destroy(this);
      return;
    }
  7. 最后,计算当前进度的方法是找出渐变开始后经过的时间,然后除以过渡的长度。产生的进度百分比乘以maxVolume的值,并应用到音频源组件的音量:

    float progress = (Time.timefadeStartTime) / fadeLength;
    source.volume = maxVolume * progress;
    }
  8. 回到 Unity 中,我们需要创建一个新的空 GameObject 并将其命名为Background

  9. 将我们的FadeIn脚本和一个音频源组件添加到我们的对象中;这些可以通过导航到组件 | 音频 | 音频源找到。

  10. 如果您还没有这样做,请在您的项目面板中创建一个Audio文件夹,并导入包含在该章节的Starting Assets文件夹中的声音文件。由于这些文件和我们当前游戏的尺寸较小,它们的默认导入设置将会正常工作。

  11. 层级窗口中选择您的Background对象,并将Background声音拖到音频剪辑槽中。

  12. 确保在音源组件中勾选了唤醒播放循环复选框。音量空间混合两个选项也需要设置为0才能让文件在整个游戏中播放,但启动时不出声。

我们在游戏中加入了背景音乐。为了使声音恒定不变,不具有方向性,我们将音乐作为 2D 的声音。我们还创建了一个脚本,以便在游戏开始时淡入音乐。这为玩家进入游戏提供了便利,防止了声音的突然冲击。如果您的背景音乐在游戏中过于嘈杂,无法听到其他声音,请降低您的Background对象的检查器面板中的最大音量值,使其更加悦耳。

背景音乐为游戏增加了很多体验。没有一些恐怖的音乐,一个恐怖的场景就不会那么恐怖。没有令人生畏的音乐,老板们就不会那么令人生畏了。为你的其他游戏寻找一些好的背景音乐。一些轻松愉快的东西对愤怒的小鸟来说会很好,而一个更加工业化和快节奏的作品会让人们在坦克战游戏中心跳加速。

戳香蕉

为了理解 3D 音频效果,我们要给香蕉添加一个声音,每次玩家触摸香蕉时都会触发。这将在玩家成功触摸到其中一根香蕉时给他们额外的反馈,同时也给出一些被触摸的香蕉的距离和方向的指示。让我们使用以下步骤来创建这种效果:

  1. 首先,我们需要一个名为BananaPoke的新脚本。

  2. 该脚本有一个变量source,用于跟踪附加到对象的音频源组件:

    private AudioSource source;
  3. 就像我们之前的脚本一样,我们使用Awake函数来查找对我们的音频源组件的引用,为我们节省了编辑器中的一点工作:

    public void Awake() {
      source = gameObject.GetComponent<AudioSource>();
    }
  4. 当玩家触摸屏幕上的香蕉时,会向调用Touched功能的香蕉发送消息。我们在第 6 章移动设备的特性中创建的BananaBounce脚本中使用了该功能来调整其运行状况。如果我们有一个音源组件,我们可以在这里再次使用它来播放我们的音效。PlayOneShot功能使用音源组件的位置和设置来播放快速音效。没有这个,我们将无法快速连续播放同一音源组件的许多音效。我们需要传递的只是播放音频片段。在这种情况下,音频剪辑被附加到音频源组件本身:

    public void Touched() {
      if(source != null)
        source.PlayOneShot(source.clip);
    }
  5. 接下来,我们需要在我们的项目面板中的Banana预设中添加我们的新脚本和一个音频源组件。

  6. BananaPoke声音文件需要从Audio文件夹拖到新的音频源组件的音频剪辑插槽。

  7. 为了在游戏开始时不会听到烦人的爆音,取消勾选在清醒状态下玩框。

  8. 接下来,我们想听听我们触摸的香蕉之间的距离差异。将空间混合设置设置为1,以便将其从 2D 音效转换为 3D 音效。

  9. 最后,我们需要将音量衰减的值更改为线性衰减,并将最大距离设置为50。这给了我们一个舒适和容易听到的音量变化,我们的声音效果基于距离。

生活在一个 3D 世界里,我们期望大多数声音来自一个特定的方向,并随着距离而消失。通过在我们的 3D 游戏中创建类似的效果,玩家能够轻松判断事物在游戏世界中的位置以及它们可能有多远。这对于玩家需要能够听到潜在敌人、障碍物或奖励的游戏来说尤其重要,这样他们就能够发现或避开它们。

我们的坦克战游戏有很多敌人可以很容易地偷袭我们,因为他们靠近时不会发出任何声音。坦克通常不被认为是安静的机器。去找一个引擎的隆隆声,或者制造出来,加到敌人的坦克上。这将会给玩家一些提示,告诉他们敌人可能在哪里,以及他们有多远。此外,不同类型的坦克有不同类型的发动机。每个引擎听起来都有点不同。所以,当你在做的时候,为你拥有的每一种坦克找到不同的引擎噪音,给玩家更多的提示什么危险就在眼前。

理解粒子系统

粒子系统给游戏的最终外观增加了很多。它们可以采取火、魔波、雨或你能想象到的许多其他效果的形式。它们通常很难被很好地创造出来,但是如果你做了,就很值得你去努力。请记住,尤其是在使用移动平台时,少即是多。较大的粒子比大量的粒子更有效。如果你的粒子系统曾经在一个小空间中包含数千个粒子,或者被复制到自身上以增加效果,你需要重新思考设计并找到一个更有效的解决方案。

粒子系统设置

每个粒子系统包含大量的组件,每个组件都有自己的设置。大多数可用的设置都可以选择常量曲线在两个常量之间随机以及在两个曲线之间随机。常量选项将是一个特定的值。曲线选项将是一个随时间沿曲线变化的设定值。这两个随机设置在各自的值类型之间选择一个随机值。起初这可能看起来很混乱,但是当你仔细研究它们时,它们会变得更容易理解。

正如您将在下面的截图和描述中看到的,我们将了解粒子系统的每一部分:

Particle system settings

  • The first portion, the Initial module, of the particle system holds all the settings used by every emitter in Unity:

    • 持续时间:表示发射器持续的时间。一个循环系统会在这段时间后重复它自己。一个非定域系统将在这段时间后停止发射新粒子。
    • 循环:此复选框指示系统是否循环。
    • 预循环:如果选中该复选框,如果循环系统已经有机会循环一段时间,它将启动循环系统。这在火把应该已经点燃的情况下是有用的,而不是在玩家进入房间时开始。
    • 启动延迟:这将在给定的秒数内停止粒子系统的发射,当它最初被触发时。
    • 开始寿命:这是单个粒子持续的秒数。
    • 起始速度:这是粒子在产生时最初移动的速度。
    • 起始大小:这个决定了一个粒子在产生的时候有多大。使用大颗粒总是比使用小颗粒更好,因此使用更多的颗粒。
    • 开始旋转:这将旋转发射的粒子。
    • 开始颜色:这是粒子产生时的颜色色调。
    • 重力修改器:这给了粒子或多或少的重力效果。
    • 继承速度:这将导致粒子在移动时获得其变换动量的一部分。
    • 模拟空间:这决定了粒子是会随着游戏对象的移动(也就是局部)而留在游戏对象身边,还是留在世界上原来的位置。
    • 唤醒时播放:如果勾选此复选框,发射器一产生或场景开始,就会开始发射。
    • 最大粒子数:这限制了该系统一次支持的粒子总数。只有当粒子发射的速度(或它们的寿命)大到超过它们的破坏速度时,这个值才会起作用。

    Particle system settings

  • The Emission module controls how fast the particles are emitted:

    • 速率:如果设置为时间,则表示每秒创建的粒子数。如果设置为距离,它表示系统移动时每单位距离的粒子数。
    • 突发:仅当速率选项设置为时间时使用。它允许您在系统的时间线中设置发射特定数量粒子的时间点。

    Particle system settings

  • The Shape module, as shown in the preceding screenshot, controls how the system emits particles. It has the following options:

    • 形状:这决定了发射点的形状。每个选项都有更多的值字段来决定其大小。
    • 球体:这是粒子从各个方向射出的点。半径参数决定了球体的大小。从壳层发射选项指定粒子是从球体表面发射还是从体积内部发射。
    • 半球:顾名思义,这是球体的一半。半径参数和从外壳发射选项在这里的工作方式与它们对球体的工作方式相同。
    • 圆锥体:这个向一个方向发射粒子。角度参数决定形状是更接近圆锥体还是圆柱体。半径参数规定了形状发射点的大小。长度参数在发射选项设置为体积体积壳时使用,以指示有多少空间可用于产卵粒子。发射选项将决定粒子从哪里发射。底座从底座发出圆盘形状的光。基壳选项从圆锥体的底部发射,但围绕形状的表面。体积会从形状内部的任何地方发出,而体积壳会从形状的表面发出。
    • 盒子:这是一个立方体形状的发射粒子。盒子 X盒子 Y盒子 Z 选项决定盒子的大小。
    • 网格:可以选择一个模型作为发射点。然后,您可以选择从组成网格的每个顶点三角形发射粒子。
    • 圆形:沿着 2D 平面从一个点发射粒子。半径决定发射的大小,决定使用多少圆。从边缘发射决定粒子是从圆的内边缘还是外边缘发射。
    • 边缘:从一条线上向单个方向发射粒子。半径参数决定了发射区域的长度。
    • 随机方向:这决定了粒子的方向是由所选形状的表面法线决定的,还是随机选择的。

    Particle system settings

  • The Velocity over Lifetime module allows you to control the momentum of the particles after they have been spawned:

    • XYZ :这些定义了沿着粒子动量的每个轴每秒的单位数。
    • 空间:这决定了速度是局部应用于系统的变换还是相对于世界。

    Particle system settings

  • The Limit Velocity over Lifetime module dampens a particle's movement if it exceeds the specified value:

    • 分离轴:这允许您定义每个轴唯一的值,以及该值是局部的还是相对于世界的。
    • 速度:这是在施加阻尼之前粒子移动的速度。
    • 阻尼:这是粒子切割速度的百分比。它可以是 0 到 1 之间的任何值。

    Particle system settings

  • The Force over Lifetime module adds a constant amount of movement to each particle over the course of its life:

    • XYZ :这些定义了每个轴需要施加多大的力。
    • 空间:这决定了力是施加在系统变换的局部还是世界空间。
    • 随机化:如果 XYZ 是随机值,这将导致在每一帧中随机选取施加的力的大小,从而对随机值进行统计平均。

    Particle system settings

  • 终生颜色模块允许你定义粒子产生后过渡的一系列颜色。

  • The Color by Speed module causes the particle to transition through the defined range of colors as its speed changes:

    • 颜色:这是要过渡的一组颜色。
    • 速度范围:这定义了粒子必须走多快,才能到达颜色范围的最小和最大端点。

    Particle system settings

  • 寿命期间的尺寸模块在粒子寿命期间改变粒子的尺寸。

  • The Size by Speed module adjusts the size of each particle, based on how fast it is going, as follows:

    • 大小:这是粒子过渡经过的调整。
    • 速度范围:这定义了每个尺寸值的最小值和最大值。

    Particle system settings

  • 生命周期内的旋转模块在粒子产生后随着时间旋转粒子。

  • The Rotation by Speed module rotates particles more as they go faster:

    • 角速度:这是粒子旋转的每秒度数速度。
    • 速度范围:如果没有设置为常数,这是角速度值的最小和最大范围。

    Particle system settings

  • 外力模块倍增风区物体的效果。风区模拟风对粒子系统和 Unity 树的影响。

  • The Collision module allows particles to collide and interact with the physical game world:

    • 如果设置为平面,可以为粒子碰撞定义多个平面。这比世界碰撞更快处理:
      • 平面:这是定义要碰撞的曲面的变换列表。粒子只会与变换的局部正 y 面碰撞。该点另一侧的任何粒子都将被破坏。
      • 可视化:这为您提供了将平面视为实体曲面或网格曲面的选项。
      • 缩放平面:这将调整可视化选项的大小。它不影响要碰撞的表面的实际大小。
      • 粒子半径:用于定义计算粒子与平面碰撞的球体大小。
    • 如果设置为世界,粒子将与场景中的每个碰撞器碰撞。这对于处理器来说是很大的负担。
      • 碰撞:这定义了粒子可以碰撞的层的列表。只有此列表中选中的图层上的碰撞器将用于碰撞计算。
      • 碰撞质量:这定义了这个粒子系统的碰撞计算有多精确。选项将精确计算每个粒子。选项将在每一帧中使用近似值和有限数量的新计算。选项的计算频率低于的计算频率。如果碰撞质量设置为体素尺寸参数指示系统估计碰撞点的精确度。
    • 阻尼:当粒子与表面碰撞时,这个消除了粒子速度的定义分数。
    • 反弹:这允许粒子保持其速度的规定分数,特别是沿着被击中表面的法线。
    • 寿命损失:这是寿命的百分比。当粒子碰撞时,这个百分比的生命从粒子中消失。当粒子的寿命随着时间或通过碰撞下降到零时,它就被移除了。
    • 最小击杀速度:如果碰撞后,粒子的速度低于该值,则粒子被破坏。
    • 发送碰撞信息:如果勾选了此复选框,附着在粒子系统和被碰撞物体上的脚本将在发生碰撞的每一帧被警告。每个帧只发送一条消息,而不是每个粒子。

    Particle system settings

  • The Sub Emitters module allows additional particle systems to be spawned at points in the life of each particle of this system:

    • 诞生列表中的任何粒子系统都将被产生,并且将在粒子第一次创建时跟随它。这可以用来制造火球或烟迹。
    • 碰撞列表会在粒子撞击某个物体时产生粒子系统。这可用于雨滴飞溅。
    • 死亡列表在粒子被破坏时产生粒子。它可以用来制造烟花爆炸。

    Particle system settings

  • The Texture Sheet Animation module causes the particle to flip through a number of particles over the course of its life. The texture used is defined in the Renderer module:

    • 平铺:定义表格中的行数和列数。这将决定可用的总帧数。
    • 动画:这给你整张单排的选择。如果该选项设置为单行,所使用的行可以随机选择,也可以使用随机行复选框和的值指定。
    • 帧随时间变化:这定义了粒子如何在帧之间转换。如果设置为常量,系统将只使用单帧。
    • 循环:这个是粒子在其生命过程中循环通过动画的次数。

    Particle system settings

  • 渲染器模块规定如何在屏幕上绘制每个粒子,如下所示:

    • 渲染模式:这定义了一个粒子应该使用哪种方法来在游戏世界中定位自己:
      • 广告牌:这个会一直对着镜头。
      • 拉伸广告牌:这将在相机处面向粒子,但它将根据相机的速度、粒子的速度或特定值拉伸粒子。
      • 水平广告牌:这是游戏世界 XZ 平面上的平面。
      • 垂直广告牌:这个会一直面向玩家,但是会一直沿着 Y 轴保持直线。
      • 如果设置为网格,可以定义一个模型作为粒子使用,而不是平面。
    • 法线方向:通过调整每个平面的法线,用于粒子的光照和阴影。值为 1 将法线直接对准相机,而值为 0 将法线对准屏幕中心。
    • 材质:这定义了用于渲染粒子的材质。
    • 排序模式:根据距离或年龄,这决定了粒子的绘制顺序。
    • 排序软糖:这导致粒子系统比正常绘制的要早。该值越高,越早在屏幕上绘制。这会影响系统出现在其他粒子系统或部分透明对象的前面还是后面。
    • 投射阴影:这决定了粒子是否会阻挡光线。
    • 接收阴影:这决定了粒子是否受到其他物体投射阴影的影响。
    • 最大粒径:这是单个颗粒允许填充的屏幕空间总量。不管粒子的真实大小如何,它永远不会填充超过屏幕的这个空间。
    • 排序图层在图层中的顺序:这些在处理 2D 游戏时使用。这些分别规定了它在什么级别上以及应该在该级别的什么位置绘制。
    • 反射探头:这些也可以用来反射世界,而不仅仅是一个粒子。当世界在反射而不是粒子时,锚定覆盖可用于定义一个自定义位置来采样反射。

那是一大堆信息。您将最常使用初始发射形状模块。它们控制着任何粒子系统的主要特征。在稍小的程度上,您将使用渲染器模块来更改粒子系统使用的纹理,并使用终生颜色模块来调整淡入度。所有这些元素,当有效地结合在一起使用时,会给你一些非常棒的效果,使任何游戏的外观都更加完美。了解他们能做什么的最好方法就是摆弄一下设置,看看会发生什么。实验和一些教程,比如接下来的几节,是成为粒子系统专家创造者的最佳途径。

创造尘埃轨迹

为了让我们的玩家更好地感受到角色实际上就在这个世界上并触摸到它,他们经常被赋予在环境中移动时踢起小尘埃云的能力。这是一个小的影响,但增加了一个很好的打磨任何游戏。我们要给我们的猴子球踢起小尘埃云的能力。让我们使用以下步骤来实现这一点:

  1. 首先,我们需要创建一个新的粒子系统,通过导航到游戏对象 | 粒子系统。命名为DustTrail
  2. 默认情况下,粒子系统会射出圆锥形的小白球。对于灰尘,我们需要一些更有趣的东西。将章节的Starting Assets文件夹中的纹理导入到项目的Particles文件夹中。这些是 Unity 提供的粒子纹理,在旧版本的引擎中有。
  3. 接下来,我们需要在Particles文件夹中创建一个新的素材。命名为DustPoof
  4. 通过转到粒子 | Alpha 混合来更改新材质的着色器属性,并将DustPoof纹理放入粒子纹理图像槽中。这使材质变得部分透明,并与世界和发射的其他粒子很好地融合。
  5. 要更改我们的DustPoof粒子系统的外观,请将材质放入渲染器模块的材质槽中。
  6. 系统中的粒子持续时间太长,走得太远,所以将启动寿命设置为0.5启动速度设置为0.2。这将使粒子在消失前从地面稍微上升。
  7. 我们还需要使粒子更适合我们猴子的大小。将起始尺寸设置为0.3,使其适当变小。
  8. 看到所有的粒子都处于完全相同的方向有点奇怪。要使方向不同,单击输入栏右侧的小向下箭头,将开始旋转更改为在两个常数之间随机选择。然后,将两个新的输入字段设置为-180180,这样所有粒子都有一个随机的旋转。
  9. 粒子的褐色是可以的,但是它并不总是与我们的水平地形的颜色和性质相一致。点击开始颜色旁边的颜色字段,使用弹出的颜色选择器窗口根据环境选择新的颜色。这将允许粒子在从我们的游戏场表面被踢起来时更有意义。
  10. 最后,对于初始模块,我们需要将模拟空间设置为世界,这样当我们的猴子移动时,粒子会被留下,而不是跟随他。
  11. 发射中,我们需要确保有足够的粒子给我们大量的灰尘被踢起来。将等级设置为20进行轻度除尘。
  12. 接下来,我们将调整形状模块,使粒子在球的整个区域下发射。确保形状设置为圆锥,角度,半径0.5
  13. With the Color over Lifetime module, we can ease the sudden appearance and disappearance of the particles. Hit the checkbox at the left-hand side of the module's name to activate it. Click on the white bar at the right-hand side of Color to open the Gradient Editor window. In Gradient Editor, clicking just above the colored bar will add a new flag that will control the transparency of the particles over their lifetime. The left-hand side of this bar corresponds to the very beginning of a particle's life, and the right-hand side corresponds to the end of its life. We need a total of four flags. One at the very beginning, with the value of Alpha set to 0, a second flag with a Location value of 20 and Alpha value of 255, the third flag at a Location of 50 and Alpha of 255, and the last flag at the very end with an Alpha value of 0. This will cause the dust particles to fade in quickly at the beginning and fade out slowly after that, easing their transition into and out of existence.
![Creating dust trails](img/4691OT_08_17.jpg)
  1. We can further ease the transition by using the Size over Lifetime module to make the particles grow and shrink as they come into and out of existence. Be sure to activate it with the checkbox by its name. By clicking on the curve bar at the right-hand side of Size, the Particle System Curves editor opens in the preview area at the bottom of the Inspector panel. Here, we can adjust any of the little diamond-shaped keys to control the size of the particles over the course of its life. Just as in the case of Gradient Editor, the left-hand side is the beginning of the particle's life and the right is the end. By right-clicking on it, we can add new keys to control the curve. To create a pop-in effect, put the first key at the bottom in the far left side. The second key should go at the top and correspond with the 0.2 value at the bottom. The third will work well at the top and 0.4 with the bottom values. The fourth should be at the far right and set at about 0.6 with the numbers on the left, which indicate the percentage of its Start Size that we set in the Initial module, as shown in the following screenshot:
![Creating dust trails](img/4691OT_08_18.jpg)
  1. 最后,为了完成我们粒子系统的外观,我们将使用生命周期旋转模块为粒子添加一点自旋。将值更改为两个常数之间的随机值,并将两个值字段设置为-4545,以使粒子在其生命过程中旋转一点。
  2. 这样我们的猴子就可以使用粒子系统,使其成为MonkeyPivot对象的子对象,并将其位置设置为0代表 X-0.5代表 Y0代表 Z 。此外,确保将 XY0Z0设置为270旋转。这将使它保持在我们猴子球的底部,并将粒子抛向空中。因为是MonkeyPivot的孩子,所以不会带着球旋转,因为我们已经让物体补偿了球的旋转。
  3. 试试看。当我们的猴子四处走动时,它会留下一条漂亮的小尘迹。这种效果可以是一种很好的抛光,尤其是如果我们根据水平仪的材质进行定制,无论是草、沙、木头、金属还是其他任何东西。
  4. 你可能会注意到,即使我们的猴子飞离了地图的边缘,效果仍在继续。我们将创建一个新的脚本,根据我们的猴子球是否真的接触到地面来切换粒子。现在创建一个名为DustTrail的新脚本。
  5. 这个脚本的第一个变量将包含对我们试图控制的粒子系统的引用。第二个将是一个标志,指示球是否实际接触地面:
```java
public ParticleSystem dust;
private bool isTouching = false;
```
  1. 我们使用OnCollisionStay功能来确定球是否接触到任何东西。该功能类似于我们在上一章中使用的OnCollisionEnter功能。当我们的一只鸟撞上什么东西的时候,这个函数被 Unity 调用,而这个函数被称为我们的球继续接触另一个碰撞器的每一帧。当它被调用时,我们只是设置我们的旗帜来标记我们正在触摸的东西:
```java
public void OnCollisionStay() {
  isTouching = true;
}
```
  1. 因为物理系统只在FixedUpdate循环中变化,这是我们用来更新粒子系统的功能。在这里,我们首先检查我们是否正在触摸什么,粒子系统当前没有发射任何东西,如其isPlaying变量所示。如果条件满足,我们使用Play功能打开粒子系统。但是,如果球没有接触任何东西,并且粒子系统正在运行,我们使用Stop功能将其关闭:
```java
public void FixedUpdate() {
  if(isTouching && !dust.isPlaying) {
    dust.Play();
  }
  else if(!isTouching && dust.isPlaying) {
    dust.Stop();
  }
```
  1. FixedUpdate功能的最后,我们将我们的标志设置为false,这样它就可以在下一帧重新更新我们是否需要打开或关闭粒子系统:
```java
  isTouching = false;
}
```
  1. 接下来,将新脚本添加到MonkeyBall对象中。正如我们在上一章中了解到的,如果我们不将其附加到与球的刚体组件相同的对象上,我们将不会收到使脚本工作所需的碰撞消息。
  2. 最后,将你的DustTrail粒子系统放到尘埃槽中,这样你的脚本就可以控制它了。
  3. Try it again. Now our monkey can easily move around and create a little dust trail until it falls off the edge of the level, goes off a jump, or otherwise ends up in the air.
![Creating dust trails](img/4691OT_08_19.jpg)

我们给了我们的猴子球踢灰尘的能力。我们还根据球是否真的接触地面来打开和关闭灰尘。这个小效果让角色感觉很好,脚踏实地。它还可以让你感觉到角色的速度,基于它后面的时间轨迹。

我们之前讨论过的另一个很好的角色基础效果是阴影。如果你还没有这样做已经,一定要给你的环境一些阴影细节。不过,你可能会注意到,由于球的部分透明性质,实时阴影对它不起作用。这就是我们在坦克上使用的斑点阴影的来源。

我们的效果也在不断运行,即使球不动。尝试根据粒子系统的刚体组件的速度来调整粒子系统是否运行。如果你需要复习的话,我们在最后一章中稍微修改了一下刚体组件的速度。对于一个额外的挑战,看看粒子系统的emissionRate变量。当球开始加速时,试着让效果有更多的粒子。

放在一起

到目前为止,我们已经独立了解了音频效果和粒子系统。他们每个人都可以为场景增加很多东西,设定气氛,给游戏一种与众不同的感觉。然而,有许多影响是无法独立存在的。例如,爆炸根本没那么令人印象深刻,除非你同时拥有视觉和听觉效果。

爆香蕉

当事物爆炸时,摧毁它们是如此令人满意。既要有粒子效应,又要有音效,才能做出合适的爆炸。我们将从创建一个爆炸预制开始。然后,我们将更新香蕉,一旦它们被摧毁,就会引发爆炸。让我们使用这些步骤来创建香蕉爆炸:

  1. 首先,我们需要创建一个新的粒子系统,并将其命名为Explosion

  2. 我们希望我们的爆炸看起来像爆炸。这就是我们的第二个粒子纹理。为其创建新材质,命名为Smoke

  3. 这次,通过转到粒子 | 添加剂来设置着色器属性。这将使用一种添加混合方法,使整个粒子看起来更亮,同时仍然混合粒子的阿尔法和后面的东西。

  4. 确保将新材质的粒子纹理属性设置为Smoke

  5. 另外,将你的Smoke材质放入粒子系统渲染器模块的材质槽中。

  6. We do not want this explosion to last too long. So, in the Initial module, set Duration to 0.5 and Start Lifetime to 1, making it all much shorter than what it was.

    当处理像短时间爆发这样的事情时,很难看出我们的变化是如何影响粒子系统的外观的。当我们完成这个粒子系统时,我们将不得不取消选中循环复选框,但是现在保持它打开会使查看和处理变得更加容易。

  7. 接下来,为了使粒子不会飞得太远,将启动速度设置为0.5,使爆炸得到遏制和集中。

  8. 为了有足够的粒子进行适当的爆炸,在发射模块中将速率设置为120

  9. To actually make the explosion seem legitimate, change Shape to Sphere in the Shape module. Also, set Radius to 0.5. If you are interested in changing the size of the explosion, adjust Radius and the Emission Rate. Increasing both will give you a larger explosion, while decreasing both will give you a smaller one.

    这种基本的爆炸效果只是视觉上的爆炸,大多数都是如此。制作一个改变环境或基于环境改变其外观的爆炸将需要额外的脚本和模型考虑,这超出了本书的范围。

  10. 我们游戏中的爆炸仍然不像爆炸那样有颜色,所有的粒子都从边缘弹出来。这就是“T2”模块的用武之地。首先,我们需要通过为 alpha 通道添加一些新的标志来消除粒子弹出。在距离边缘大约百分之20的地方添加两个新的标志,并调整所有四个标志,这样粒子在开始时淡入,在结束时淡出。

  11. The flags along the bottom of the gradient bar of Gradient Editor control the colors that the particle will transition through over the course of its life. For a decent explosion, we are going to need two more flags, one that is placed one-third of the way in and one flag at two-thirds, spacing all four of them evenly. Explosions tend to start with a moderately bright color, followed by a bright color at the peak of the explosion's energy, then another medium bright color as the energy starts to dissipate, and finally black when all of the energy is gone. Each color you pick will affect the color of the explosion. For a normal explosion, select yellows and oranges. For a sci-fi space explosion, you can select blues or greens. Or, maybe it is an alien spore cloud with the use of purples. Use your imagination and pick something appropriate for what you want to explode.

![Exploding bananas](img/4691OT_08_20.jpg)
  1. 现在我们已经设置好了,确保在清醒状态下播放被勾选,所以爆炸会在创建的那一刻开始,取消勾选循环,这样就不会永远播放了。如果你想在这一点上测试你的粒子系统,看看当选择任何粒子系统时出现在你的场景窗口右下角的停止模拟暂停按钮。这些按钮就像音乐播放器的按钮一样工作,控制粒子系统的回放。
  2. 如果我们现在开始制造爆炸,他们会在产生他们最初的粒子群后坐在场景中,尽管玩家永远不会看到他们。这就是为什么我们需要一个新的脚本来处理它们。创建一个新的脚本并命名为Explosion
  3. 这个脚本只有一个变量,那就是跟踪指示其存在的粒子系统:
```java
public ParticleSystem particles;
```
  1. 它还有一个单一的功能。Update功能检查每一帧,看粒子系统是否存在,或者是否已经停止播放。无论哪种情况,整体对象都会被破坏,这样我们就可以节省资源:
```java
public void Update() {
  if(particles == null || !particles.isPlaying)
    Destroy(gameObject);
}
```
  1. 接下来,我们需要向Explosion对象添加我们的新脚本。另外,将粒子系统组件拖到脚本组件中的粒子槽中。
  2. 为了让爆炸被听到,我们还需要给Explosion对象添加一个音频源组件。
  3. 确保其唤醒播放框已选中。为了使声音在三维空间中有意义,将空间混合属性设置为1。另外,将线性滚降50设置为最大距离,这样我们就可以听到了。
  4. 我们的香蕉发出和汽车一样的爆裂声没有多大意义。相反,我们有一个很好的小爆裂声,将最后的触摸与那些只会降低香蕉健康的触摸区分开来。为此,将BananaPop音频文件设置在音频源组件上的音频剪辑插槽中。
  5. 我们所有的爆炸设置就位后,用Explosion对象创建一个新的预设,并将其从场景中删除。
  6. 接下来,我们需要更新BananaBounce脚本,以便在爆炸耗尽生命值时实际产生爆炸。现在打开它。
  7. 首先,我们在脚本的开头添加一个新的变量。这将简单地记录香蕉耗尽健康后我们想要产卵的预制体:
```java
public GameObject explosion;
```
  1. 接下来,我们需要在使用Destroy函数之后,在Touched函数中添加一行。这条线只是在香蕉的位置创建了爆炸的新实例:
```java
Instantiate(explosion, transform.position, transform.rotation);
```
  1. Finally, find your Banana prefab in the Project panel and drop the Explosion prefab into the new Explosion slot. If you don't, the explosion will never be created and Unity will give you an error every time a banana runs out of health.
![Exploding bananas](img/4691OT_08_21.jpg)

正如你在前面的截图中看到的,我们已经创建了一个爆炸。借助于 Unity 旧粒子系统的一些纹理,我们使它看起来像一个爆炸,而不仅仅是一团彩色的球,否则它会是。我们也给了爆炸一个音效。结合粒子系统和音频源,我们可以创建许多效果,比如我们的爆炸,如果你只使用其中一个,它会很弱。我们还更新了我们的香蕉,这样当它们被玩家破坏时就会产生爆炸。试着摆弄香蕉音频的平衡、每次触摸香蕉时的音量差异以及爆炸本身。我们可以用粒子系统在视觉上给玩家提供的信息越多,用音频源在听觉上给玩家提供的信息越多,效果就越好。

香蕉不是这个世界上唯一会爆炸的东西。在第二场比赛中,我们摧毁了刚刚消失的坦克。尝试在坦克战游戏中加入一些新的爆款。每次坦克被摧毁,它都应该光荣地爆炸。此外,坦克的子弹无论击中什么都会爆炸。试着在被击中的地方引发爆炸,而不是移动红色球体。这将让玩家对他们所射击的东西有更好的感觉。

愤怒的小鸟游戏也可以使用一些爆款,尤其是黑鸟。每次有东西被破坏,它应该会抛出某种粒子,发出一点点噪音。否则,当事情突然消失时,它会继续看起来有点奇怪。

总结

在本章中,我们学习了 Unity 中的特殊效果,特别是音频和粒子系统。我们从了解 Unity 如何处理音频文件开始。通过给球添加背景音乐和一些吱吱声,我们将所学付诸实践。我们继续了解粒子系统,并为球创建了一个尘埃轨迹。最后,我们将这两种技能组合在一起,为收集到的香蕉制造爆炸。粒子系统和音频效果为游戏的最终润色和外观增加了很多。

在下一章中,我们将通过研究 Unity 中的优化来共同完成我们的游戏体验。我们将看看为跟踪性能提供的工具。我们还将创建自己的工具来跟踪脚本性能的特定部分。我们将探讨素材压缩和其他我们可以改变的点,以最大限度地减少应用程序占用空间。最后,将讨论在使用游戏和 Unity 时将延迟最小化的关键点。