6 - 音频与粒子系统入门

本文将初步介绍UE5中有关音频系统和粒子系统的内容,包括一些概念,如何通过C++播放声音,通过C++生成粒子等操作。

音频系统

UE5中的音频

游戏中通常包括以下两种类型的声音:

  • 2D声音:不会考虑听者的距离和方向,通常用于播放音乐;
  • 3D声音:根据玩家的位置调整音量高低和左右方向,通常用于播放音效。

UE5中的声音格式文件主要为.wav.mp3

音频资产

UE5中音频相关的资产和类如下:

  • Sound Base:包含音频的资产,在C++/蓝图中用于引用可播放的音频文件。
  • Sound Wave:继承自Sound Base,表示已导入UE5的音频文件。
  • Sound Cue:继承自Sound Base,包含与衰减、循环播放、混合等音频相关的逻辑。
  • Sound Class:可以将音频文件分组,并管理如音量、音调等设置。例如将所有音效分组到SFX声音类中,将所有对话分组到Dialog声音类中。
  • Sound Attenuation:指定3D声音的衰减方式,例如在多远距离时开始降低音量,在多远距离时听不见等。
  • Audio Component:用于Actor的组件,可以管理音频文件的播放和它们的属性。

Meta Sounds

UE5还新增了一个名叫Meta Sounds的新音频系统,允许开发者使用数字信号处理技术来创建声音。

详见MetaSounds in Unreal Engine

操作音频

导入音频

在内容浏览器中新建一个Audio文件夹,将音频文件拖进去,双击打开后发现有好多可编辑属性。这里主要关注音效Sound:

这里能调音频是否循环,音量,音调以及声音所属的类。接下来新建一个声音类Dodgeball,让这个音频属于Dodgeball类,这样就能通过声音类来编辑所属音频资产的属性了。

播放声音

首先在投射物的头文件中添加如下成员:

// 躲避球反弹时播放的声音
UPROPERTY(EditAnywhere, Category = Sound)
USoundBase* BounceSound;

然后在源文件中添加GameplayStatics对象用到的头文件:

#include "Kismet/GameplayStatics.h"

最后在球反弹的时候调用GameplayStatics对象的PlaySoundAtLocation()播放弹跳的声音,条件是BounceSound有效且NormalImpulse足够大:

void ADodgeballProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor,
                                 UPrimitiveComponent* OtherComp, FVector ImpulseNormal, 
                                 const FHitResult& HitResult)
{
	// 播放反弹声音
	if (BounceSound != nullptr && ImpulseNormal.Size() > 600.f)
	{
		UGameplayStatics::PlaySoundAtLocation(this, BounceSound, GetActorLocation(),
		                                      1.0f, FMath::RandRange(0.7f, 1.3f));
	}
    
    ...
}

其中,PlaySoundAtLocation()负责在指定位置播放一个3D声音,参数如下:

  • WorldContextObject:世界上下文对象,这里传入this;
  • SoundBase:要播放的声音;
  • Location:声音的位置;
  • VolumeMultiplier:音量的高低,例如2.0就会让音量变成2倍;
  • PitchMultiplier:音调的高低,这里用[0.7 ~ 1.3]之间的随机数。

如果想要播放2D声音,可以使用GameplayStatics对象的PlaySound2D()方法。

最后编译代码,修改相应蓝图类即可。

音效衰减

注意到无论角色距离弹跳的躲避球有多远,声音总是以相同的音量播放。接下来添加音效衰减资产BounceAttenuation,让球的音量随距离增加而衰减。

音效衰减资产的编辑画面(主要是音量的衰减)如下:

可以调整内部半径 Inner Radius(距离超过此半径时开始衰减)和衰减距离 Falloff Distance(超过此距离后听不到声音)。

更多关于音效衰减资产的信息详见:Sound Attenuation in Unreal Engine

接下来在投射球的蓝图类中添加对应属性:

// 躲避球反弹时音效的音效衰减
UPROPERTY(EditAnywhere, Category = Sound)
USoundAttenuation* BounceSoundAttenuation;

然后修改PlaySoundAtLocation

UGameplayStatics::PlaySoundAtLocation(this, 
                                      BounceSound, 
                                      GetActorLocation(), 
                                      1.0f, 
                                      FMath::RandRange(0.7f, 1.3f), 
                                      0.0f, 
                                      BounceSoundAttenuation);

其中新增了两个参数,声音开始的时间和声音衰减资产。

最后编译代码,更改蓝图类,应用成果。

播放BGM

需要使用Audio Component来播放BGM,因此要创建一个继承于Actor类的C++类MusicManager。在头文件处添加如下属性:

UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
class UAudioComponent* AudioComponent;

在构造函数处编写如下代码:

AMusicManager::AMusicManager()
{
	PrimaryActorTick.bCanEverTick = false;
	AudioComponent = CreateDefaultSubobject<UAudioComponent>(TEXT("Music Component"));
}

然后基于此类创建对应的蓝图类BP_MusicManager,配置要播放的BGM,然后拖到场景中就行了。并且Audio组件是循环播放的,也不需要考虑配置是否循环播放的问题。

粒子系统

粒子系统是许多粒子的几何,这些粒子可能具有不同的图像、形状、颜色和大小。UE5中有两种创建粒子系统的工具:Cascade和Niagara。其中Niagara是UE5新增的更新更复杂的粒子系统。

简单操作

要想在C++中使用粒子系统,得先在使用它的类上添加如下属性:

// 发生碰撞时产生的粒子特效
UPROPERTY(EditAnywhere, Category = Particles)
class UParticleSystem* HitParticles;

接下来需要调用GameplayStatics对象中的SpawnEmitterAtLocation()函数来生成粒子:

// 播放粒子
if (HitParticles != nullptr)
{
    UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), HitParticles, GetActorTransform());
}

其中,SpawnEmitterAtLocation()的一种参数列表如下:

  • World :粒子生成所处的世界,使用GetWorld()获取;
  • EmitterTemplate:UParticleSystem*,要生成的粒子系统;
  • SpawnTransform :粒子在世界空间中的变换信息;

此外,如果想要将一个粒子系统附加到Actor上,让它随Actor移动而移动,需要使用GameplayStatics对象提供的SpawnEmitterAttached()函数。

最后编译完代码,去对应蓝图类中设置要产生什么粒子就可以了:

参考资料

  • 中文翻译:《UE5 C++ 游戏开发完全学习教程》

  • 英文原版:《Elevating Game Experiences with UE5》