在虚幻引擎中程序化地控制心跳速度

作者:光茧|Phocoon
2023-08-16
0 0 0

前言

最近和朋友组成了一个不大的工作室,正在开发一款暂定名为《大荒鬼差》的游戏。可以说的部分是,这是款注重探索、感知看不见的鬼,以及使用各种机关陷阱捉妖抓鬼的游戏。游戏中有很多关于对鬼感知的设计,其中一个细节设定是:玩家在鬼附近时,会有心跳声强化氛围、提供反馈——越是接近鬼,心跳越强烈。心跳既要营造紧张感,同时还要给玩家提供足够的信息,且听起来不违和、不死板。作为整个游戏第一块与声音相关的部分,我安排自己来做实现(非常有私心地想自己玩玩新的东西)。

先试最直观的方案

首先,寻找一个心跳的音效。浏览过收藏的各种免费商用的音效网站后,找到了一个非常干净的心脏两连跳音频,它的波形也很像心跳。

导入 UE,直接修改播放速度,搞定了。轻松愉快......吗?

并没有。实际上,直接播放音频是没有播放速度这个选项的,对于音频,直接的修改选项只有音量与音高。想要心跳加快,还需要引入其他的系统。

较为简单的替代方案

在多个版本的迭代中,UE 提供了多个声音处理系统,先用相对较老但也更简单易用的 Sound Cue 试一下。

官方文档在这里

与 UE 中绝大部分编辑器一样,Sound Cue 也有一个节点化的编辑界面。整个系统支持的节点并不多,如下图:

可以看到,没有可以直接调节音频播放速度的节点。为了让心跳加速,我们要自己再想点办法。

拆分、重组心跳

先拆解一下心跳声音的构成方式。心脏循环(跃动)一次会产生两个声音,分别是收缩和舒张,通常收缩的声音更厚重,舒张的声音则相对弱一些。其中时间间隔也有变化,同一次心脏跳动的收缩与舒张的声音间隔,比两次心跳之间的时间间隔更短。这个时间比例基本在 1:2 左右。

根据我们的结论,先用 Logic Pro 将之前的音频进行拆解。

于是得到了两个收缩音效与两个舒张音效。

这样拆开之后,还额外带来了一个好处:如果以一次收缩一次舒张作为一个完整的心跳循环,拆开之后的音频一共可以产生四种不同的排列组合。每次心跳的时候随机播放一种组合,可以尽可能减少玩家对重复声音的厌倦,让整个音效听起来不那么死板。

确定了方案,我们来看在 Sound Cue 中的具体实现方式。

  • 分别导出刚刚的 4 个音频,导入 UE,拖入到 Sound Cue 的编辑界面;
  • 收缩音效一组,舒张一组,分别连接到 Random(随机)节点,这样每次播放的时候会随机选取一个收缩音效和一个舒张音效;
  • 我第一次的想法是播完收缩音效后播放舒张音效,所以使用了 Concatenator(串联器)节点。但是根据前面的分析,收缩与舒张之间的时间、舒张与下一次收缩之间的时间都需要调节,按当前设计,收缩与舒张的间隔只能增加不能减少,所以 Concatenator 不能满足需求;
  • 能够满足需求的方式是使用一个 Mixer(混音器),加一个 Delay(延迟)节点,让舒张音效通过 Delay 节点延后一小段时间播放,再将两个有所错位的音频连入同一个 Mixer;
  • 现在已经构成了一次完整的心跳,Sound Cue 支持在节点上直接试听当前节点的结果,此时在 Mixer 节点上试听,多次播放就可以听到多种不同的心跳效果;
  • 因为我们的心跳是一个连续音效而不是单次效果,所以在获得了单个心跳音效后,我们还需要再增加一个 Delay 来表示两次心跳之间的间隔,接着再连接一个 Loop(循环)节点,最终连上输出节点。此时播放整个 Sound Cue 效果,就可以听到无限延续的心跳声;
  • 要加快心跳,只需要修改两个 Delay 节点的时长。因为时间计算是从收缩的起始时间开始的,所以注意,需要保持一个 1:3 的比例。

回到最开始的需求。现在的心跳音效已经比较生动了,也有了可以控制速度的方式,接下来就需要将这个音效交给游戏程序,根据情况计算并设置心跳速度即可。

然而事情没有这么简单,Sound Cue 中的数值调节只能手动设定,UE 官方并没有提供通过运行时的程序控制这些变量的方法。

PS:Delay 中倒是可以设定随机的延迟时间,但那也只会得到一个心律不齐的心跳音效。

PPS: 在这款游戏里,一个心律不齐的心跳音效或许也有用武之地。

为了程序化地控制心跳速度,我们将会掏出今天的最终武器,MetaSounds 系统。

来吧,元(Meta)起来

Unreal Engine 5 introduces MetaSounds, a high-performance audio system that provides audio designers with complete control over a Digital Signal Processing (DSP) graph for the generation of sound sources.

根据官方介绍,MetaSounds 是一个[次世代][图形化][高性能][音频数字信号]处理系统。理论上,音频设计师可以设计出在游戏运行时动态处理音频甚至生成音频的节点图。

官方文档在这里

这套系统完全可以从简单的波开始,通过各种调制制造音效。但今天,我们只应用其动态传入控制参数的功能,补全在 Sound Cue 那个方案中缺失的部分。

整体逻辑与在 Sound Cue 中一样,两组声音,各自随机选择一个,给舒张音效加上 Delay,再用 Mixer 一起输出,循环起来就是心跳音效。接下来重点说一下不同的部分:

  • 首先是音频的导入方式,MetaSounds 采用的是参数化的输入,所以音频素材是类型为` Wave Asset` 的输入参数,由于我们要在多个音频中随机,所以最终是参数类型为 Wave Asset 的数组(我们需要收缩与舒张各一个数组);

  • 其次需要定义一下调节心跳速率的变量。根据之前的设计,心跳速度使用两个 Delay 的时间来定义,类型是时间,又因为我们的两个时间间隔是有数学关系的,所以只需要定义一个参数,计算另外一个就可以了(这里又用到了 MetaSounds 的一个重要功能,就是数学计算);

  • 再次是循环的方式。Sound Cue 是在最后添加一个循环节点,而 MetaSounds 是在整个播放逻辑之前加入 Repeat Trigger(重复触发器)。

到这里,所需音效就基本完工了,但我们还要再补充两个细节。

  • MetaSounds 构造的音频资产默认是有一个 OneShot(一次性)接口的,我们实现的心跳音效是持续不断的,所以要将这个接口删掉;
  • 通常来讲,随着心跳加速,心跳的音量也会增强,所以我们再加入一个浮点型的变量作为控制音量的参数,连接到最终 Mixer 的增益上,整个音效就更加生动了。

小结与展望

得到 MetaSounds 的资产,我们就可以在游戏角色的运行时逻辑中调用播放,并根据距离设定心跳间隔和音量了。这部分比较简单,但由于我们游戏中的心跳计算并不只与距离有关(稍有点复杂),所以采用 C++ 来实现。这里就不贴出来了,直接控制心跳的话可以参考这个图。

以上就是今天的全部内容。

本篇日志记录的,都是基于 UE 官方教程匹配己方需求的应用,可能不是最佳的实践,也还有很多改进空间,但我觉得思路很有趣,使用的工具也是之前完全没有接触过的,所以值得记录和分享一下。如果真的有人能看到这里,希望你能有所收获,同时祝愿我们的游戏可以顺利完工。

随缘更新,各位有缘再见。

本文为用户投稿,不代表 indienova 观点。

 分享这篇文章

您可能还会对这些文章感兴趣

参与此文章的讨论

暂无关于此文章的评论。

您需要登录或者注册后才能发表评论

登录/注册