赞
踩
前面,我们将火球的转向和人物的转向问题解决了,火球术可以按照我们的想法朝向目标发射。现在,我们解决接下来的问题,在角色释放火球术时,会产生释放音效,火球也会产生对应的音效,在火球击中目标时,我们需要一个爆炸特效以及爆炸音效。
接下来,我们将一步步实现它们。
要在代码里面能够使用特效,我们需要在Build.cs里面增加它的依赖,在UE5里面,我们已经修改为使用Niagara粒子系统了。
PrivateDependencyModuleNames.AddRange(new string[] { "GameplayTags", "GameplayTasks", "NavigationSystem", "Niagara" });
我们增加两个可以设置的属性,分别用于设置击中特效和击中音效
UPROPERTY(EditAnywhere)
TObjectPtr<UNiagaraSystem> ImpactEffect;
UPROPERTY(EditAnywhere)
TObjectPtr<USoundBase> ImpactSound;
增加一个私有函数,用于播放相关特效和音效
void PlayImpact() const;
在函数实现这里,调用对应函数去播放
void AProjectile::PlayImpact() const
{
//播放音效
UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(), FRotator::ZeroRotator);
//播放粒子特效
UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation());
}
接下来增加一个变量,用于判断当前火球是否和其它物体产生了碰撞, 这个变量设置为私有即可
bool bHit;
接下里就是设置重叠回调,在重叠回调里面,我们要调用播放函数,然后判断对当前对象是否拥有权威性,如果拥有权威性,在触发重叠后,销毁它,如果没有,将bHit设置为true,代表它已经触发了重叠事件,并且已经播放了几种特效,但是没有对火球的控制权,无法自身直接销毁。
void AProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { PlayImpact(); //在重叠后,销毁自身 if(HasAuthority()) { Destroy(); } else { //如果对actor没有权威性,将bHit设置为true,证明当前已经播放了击中特效 bHit = true; } }
接着我们要重写销毁事件
virtual void Destroyed() override;
在销毁事件的实现这里,如果没有对火球的权威性控制权,并且现在还没有触发碰撞体的重叠事件,那么我们在销毁时播放击中特效。
void AProjectile::Destroyed()
{
//如果没有权威性,并且bHit没有修改为true,证明当前没有触发Overlap事件,在销毁前播放击中特效
if(!bHit && !HasAuthority())
{
PlayImpact();
}
Super::Destroyed();
}
编译代码,打开UE进行测试,首先将配置项设置上对应的Niagara粒子特效和音效
为了防止技能太快在没有创建火球之前被销毁,我们延迟0.5秒结束技能
运行,选择人物释放技能击中
火球的击中特效我们制作出来了 ,接下来,我们实现一下技能释放时的音效,这个音效需要在蒙太奇里面添加,我们在角色释放技能的那一帧,给一个播放音效的通知。
打开释放技能的蒙太奇,在标准位置添加一个播放音效的通知
选中添加的通知,可以在右侧调整相关参数,我这里就添加一个声音
现在释放火球有了音效,并且击中时有击中音效和击中特效,接下来我们添加一下火球在移动中,发出的音效,它是一个循环音效。
首先打开代码编辑器,添加一个用于添加音效文件的变量,然后添加一个存储生产的循环音效的变量,由于它是一直循环播放的,所以我们需要在Actor被销毁时,一同销毁掉这个音效组件。
//移动循环音效
UPROPERTY(EditAnywhere)
TObjectPtr<USoundBase> LoopingSound;
//储存循环音效的变量,后续用于删除
UPROPERTY()
TObjectPtr<UAudioComponent> LoopingSoundComponent;
在Actor的事件开始回调时,添加一个附加在根组件的音效,这样可以让音效跟随组件移动。
void AProjectile::BeginPlay()
{
Super::BeginPlay();
Sphere->OnComponentBeginOverlap.AddDynamic(this, &AProjectile::OnSphereOverlap);
//添加一个音效,并附加到根组件上面,在技能移动时,声音也会跟随移动
LoopingSoundComponent = UGameplayStatics::SpawnSoundAttached(LoopingSound, GetRootComponent());
}
如果我们添加的是循环播放的音效,它无法被停止,所以,我们将在火球术结束时,将音效组件暂停。创建的附加音效默认会在音效播放完成或者暂停后自动销毁。
void AProjectile::PlayImpact() const
{
//播放声效
UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(), FRotator::ZeroRotator);
//播放粒子特效
UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation());
//将音乐停止后会自动销毁
LoopingSoundComponent->Stop();
}
接着编译打开UE,我们找到对应的音频文件,将其设置为默认循环,这样在停止之前,它会一直播放
然后将音效文件设置上去
如果火球没有击中任何内容,它将会一直存在,所以,我们需要实现设置它的存在时间,如果它在一定时间内没有击中任何物体,那它将会自行销毁。
首先创建一个私有属性,可以在面板修改它的存在时间,单位秒。
private:
//此物体的存在时间
UPROPERTY(EditDefaultsOnly)
float LifeSpan = 15.f;
然后在事件开始时设置它的生存时间,如果值设置为0,它的生存时间为无限
void AProjectile::BeginPlay()
{
Super::BeginPlay();
//设置此物体的存在时间
SetLifeSpan(LifeSpan);
...
}
Projectile.h
// 版权归暮志未晚所有。 #pragma once #include "CoreMinimal.h" #include "GameFramework/Actor.h" #include "Projectile.generated.h" class UNiagaraSystem; class UProjectileMovementComponent; class USphereComponent; UCLASS() class AURA_API AProjectile : public AActor { GENERATED_BODY() public: // Sets default values for this actor's properties AProjectile(); UPROPERTY(VisibleAnywhere) TObjectPtr<UProjectileMovementComponent> ProjectileMovement; protected: // Called when the game starts or when spawned virtual void BeginPlay() override; virtual void Destroyed() override; UFUNCTION() void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult); private: //此物体的存在时间 UPROPERTY(EditDefaultsOnly) float LifeSpan = 15.f; void PlayImpact() const; bool bHit; //碰撞球 UPROPERTY(VisibleAnywhere) TObjectPtr<USphereComponent> Sphere; //击中粒子特效 UPROPERTY(EditAnywhere) TObjectPtr<UNiagaraSystem> ImpactEffect; //击中音效 UPROPERTY(EditAnywhere) TObjectPtr<USoundBase> ImpactSound; //移动循环音效 UPROPERTY(EditAnywhere) TObjectPtr<USoundBase> LoopingSound; //储存循环音效的变量,后续用于删除 UPROPERTY() TObjectPtr<UAudioComponent> LoopingSoundComponent; };
Projectile.cpp
// 版权归暮志未晚所有。 #include "Actor/Projectile.h" #include "NiagaraFunctionLibrary.h" #include "Components/AudioComponent.h" #include "Components/SphereComponent.h" #include "GameFramework/ProjectileMovementComponent.h" #include "Kismet/GameplayStatics.h" // Sets default values AProjectile::AProjectile() { // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = false; bReplicates = true; //服务器负责计算并更新Actor的状态,然后通过网络将这些更新复制到所有连接的客户端上。 //初始化碰撞体 Sphere = CreateDefaultSubobject<USphereComponent>("Sphere"); SetRootComponent(Sphere); //设置其为根节点, Sphere->SetCollisionEnabled(ECollisionEnabled::QueryOnly); //设置其只用作查询使用 Sphere->SetCollisionResponseToChannels(ECR_Ignore); //设置其忽略所有碰撞检测 Sphere->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Overlap); //设置其与世界动态物体产生重叠事件 Sphere->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Overlap); //设置其与世界静态物体产生重叠事件 Sphere->SetCollisionResponseToChannel(ECC_Pawn, ECR_Overlap); //设置其与Pawn类型物体产生重叠事件 //创建发射组件 ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>("ProjectileMovement"); ProjectileMovement->InitialSpeed = 550.f; //设置初始速度 ProjectileMovement->MaxSpeed = 550.f; //设置最大速度 ProjectileMovement->ProjectileGravityScale = 0.f; //设置重力影响因子,0为不受影响 } // Called when the game starts or when spawned void AProjectile::BeginPlay() { Super::BeginPlay(); //设置此物体的存在时间 SetLifeSpan(LifeSpan); Sphere->OnComponentBeginOverlap.AddDynamic(this, &AProjectile::OnSphereOverlap); //添加一个音效,并附加到根组件上面,在技能移动时,声音也会跟随移动 LoopingSoundComponent = UGameplayStatics::SpawnSoundAttached(LoopingSound, GetRootComponent()); } void AProjectile::Destroyed() { //如果没有权威性,并且bHit没有修改为true,证明当前没有触发Overlap事件,在销毁前播放击中特效 if(!bHit && !HasAuthority()) { PlayImpact(); } Super::Destroyed(); } void AProjectile::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) { PlayImpact(); //在重叠后,销毁自身 if(HasAuthority()) { Destroy(); } else { //如果对actor没有权威性,将bHit设置为true,证明当前已经播放了击中特效 bHit = true; } } void AProjectile::PlayImpact() const { //播放声效 UGameplayStatics::PlaySoundAtLocation(this, ImpactSound, GetActorLocation(), FRotator::ZeroRotator); //播放粒子特效 UNiagaraFunctionLibrary::SpawnSystemAtLocation(this, ImpactEffect, GetActorLocation()); //将音乐停止后会自动销毁 if(LoopingSoundComponent) LoopingSoundComponent->Stop(); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。