简单的爆炸

你可以使用粒子系统创建一个逼真的爆炸效果,但是其中的动力学可能有些复杂。本质上,爆炸不过是向外的粒子脉冲(爆发),不过你可以做一些简单的修改,让爆炸看起来更逼真。

A particle system explosion during development

开发阶段的粒子系统爆炸

粒子的时间轴

一个简单的爆炸会产生一个在所有方向上迅速向外膨胀的火焰球。爆炸的初始阶段具有巨大的能量,因此非常帜热(即明亮),并且火焰非常快速地移动。然后,能量快速消散,导致火焰的膨胀减慢和冷却(即变得不明亮)。最终,随着所有燃料被烧尽,火焰将减弱,并且很快完全消失。

爆炸粒子的生命周期通常很短,你可以在其生命周期中改变多个不同属性,以模拟这种效果。粒子的初始移动速度非常快,然后随着远离爆炸中心,它的速度将急剧降低。另外,颜色应该从明亮开始,然后变暗,最终逐渐变淡直至透明。最后,随着生命周期减小粒子的尺寸,将产生火焰因燃料耗尽而消散的效果。

实现

从默认的粒子系统对象开始(菜单:GameObject > Create General > Particle System),找到 形状 Shape 模块,设置发射形状为一个小 球 Sphere,并设置半径为 0.5 单位。粒子标准资源包中包含了一个名为 Fire Add 的材质,非常适合用于爆炸(菜单:Assets > Import Package > Particles)。你可以使用 Renderer 模块为粒子系统设置材质。展开 Renderer 后,还应该禁用 投射阴影 Cast Shadows接收阴影 Receive Shadows,因为爆炸的火焰应该发射光而不是接收光。

在这个阶段,粒子系统看起来像从中心点抛出了许多小火球。爆炸当然应该立即产生大量的粒子脉冲。在 发射 Emission 模块,你可以设置 速率 Rate 为 0,并在时间 0 点添加一个单独的粒子 脉冲 Burst。该脉冲中的粒子数量取决于暴躁的大小和强度,不过,开始时最好设置为 50 个粒子。设置好这个脉冲后,现在粒子系统开始看起来更像是爆炸了,但是它相当缓慢,并且火焰看起来长时间炫富。在粒子系统模块中(与游戏对象同名,例如 Explosion),设置 系统持续时间 Duration粒子生命周期 Start Lifetime 为 2 秒。

你也可以使用 随生命周期改变大小 Size Over Lifetime 模块创建火焰耗尽燃料的效果。设置大小曲线为预设的『斜降 ramp down』(即,大小从 100% 开始,然后减小为 0)。为了使火焰变暗和变淡,开启 随生命周期改变颜色 Color Over Lifetime 模块,设置颜色渐变,从左侧的白色开始,到右侧的黑色结束。因为材质 Fire Add 材质使用了 Additive 着色器,所以颜色属性的明暗度也控制了粒子的透明度;当颜色渐变为黑色时,火焰将变得完全透明。并且,当绘制的粒子彼此重叠时,Additive 材质支持粒子亮度的叠加。这有助于增强爆炸开始时的明亮闪光,此时全部粒子紧靠在一起。

现在,爆炸正在形成,但是它看起来好像发生在太空中。粒子从被抛出到消失,以恒定的速度传播。如果游戏发生在太空中,那么这确实可能是你想要的效果。但是,发生在大气中的爆炸将被周围的空气阻碍并衰减。开启 随生命周期抑制速度 Limit Velocity Over Lifetime,设置 速度 Speed 为约 3.0,设置 抑制 Dampen 分数为约 0.4,你应该可以看到爆炸随着进度损失了一些强度。

最后要注意的是,随着粒子远离爆炸中心,它们各自的形状变得更加可辨认。特别是,可以看到所有粒子具有相同的大小和相同的旋转,显而易见,同样的图形被重复用于每个粒子。避免这种情况的一个简单方法是,在生成粒子时,为粒子的大小和大小增加一点随机变化。在检视视图顶部的 粒子系统 模块中,点击 初始大小 Start Size初始旋转 Start Rotation 右侧的小箭头,把它们都设置为 在两个常量之间随机 Random Between Two Constants。对于旋转,将两个值设置为 0 和 360(即完全随机地旋转)。对于大小,设置为 0.5 和 1.5,以提供一些变化,并且不用担心会有大多巨大或微小的粒子。现在,你应该看到粒子图形的重复不太明显了。

用法

在测试期间,打开 Looping 属性是有用的,以便你可以反复看到爆炸,但是在完成的游戏中,你应该关闭它,以使爆炸只发生一次。当为一个可能爆炸的对象(例如燃油箱)设置爆炸效果时,你需要为它添加粒子系统组件,并禁用 唤醒时播放 Play On Awake 属性。然后,你可以根据需要触发爆炸效果。

  1. void Explode() {
  2. var exp = GetComponent<ParticleSystem>();
  3. exp.Play();
  4. Destroy(gameObject, exp.duration);
  5. }

在某些情况下,爆炸发生在撞击点。如果爆炸来自某个对象(例如手榴弹),那么你可以在延迟一段时间后或当它与目标接触时,调用上面编写的 Explode 函数。

  1. // Grenade explodes after a time delay.
  2. public float fuseTime;
  3. void Start() {
  4. Invoke("Explode", fuseTime);
  5. }
  6. // Grenade explodes on impact.
  7. void OnCollisionEnter(Collision coll) {
  8. Explode();
  9. }

译注:fuse time 引信时间。

当爆炸来自一个不可见的游戏对象时(例如,速度太快以至于无法看到的子弹),你可以在适当的位置实例化爆炸。例如,你可以用 射线 raycast 确定接触点。

  1. // On the explosion object.
  2. void Start() {
  3. var exp = GetComponent<ParticleSystem>();
  4. exp.Play();
  5. Destroy(gameObject, exp.duration);
  6. }
  7. // Possible projectile script.
  8. public GameObject explosionPrefab;
  9. void Update() {
  10. RaycastHit hit;
  11. if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit)) {
  12. Instantiate (explosionPrefab, hit.point, Quaternion.identity);
  13. }
  14. }

更进一步

这里开发的爆炸非常基础,不过你可以修改它的各个模块,以获得想要的精确效果。

所使用的粒子图形将极大地影响玩家如何『理解』爆炸。许多微小的、单独可识别的火焰,暗示燃烧的碎片正在被抛出。更大的、完全不可移动的部分,看起来更像是由被破坏的燃料箱产生的火球。通常,你需要同时更改多个属性才能实现这种效果。例如,火球在消失前将持续更长的时间和较小的膨胀,而剧烈的爆炸可能在相当一段距离内散布燃烧的碎片。

爆炸示例中的几个属性被设置为随机值,但是其他许多其他属性都有一个 在两个常量/曲线之间随机 Random Between Two Constants/Curves 选项,你可以使用这些属性添加各种变化。改变大小和旋转可以避免最明显的粒子重复问题,你也可以考虑为 初始延迟 Start Delay初始生命周期 Start Lifetime初始速度 Start Speed 添加一些随机性。轻微的变化有助于增强爆炸效果的自然性和不可预测性,而不是受控的机械式过程。较大的变化暗示一场『放射性』爆炸。例如,改变 初始延迟Start Delay 将产生不再突然、爆发更慢的爆炸,可能是因为车辆的燃油箱被单独点燃。