40. UE5 RPG给火球术增加特效和音效

前面,我们将火球的转向和人物的转向问题解决了,火球术可以按照我们的想法朝向目标发射。现在,我们解决接下来的问题,在角色释放火球术时,会产生释放音效,火球也会产生对应的音效,在火球击中目标时,我们需要一个爆炸特效以及爆炸音效。

接下来,我们将一步步实现它们。

添加C++依赖

要在代码里面能够使用特效,我们需要在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 propertiesAProjectile();UPROPERTY(VisibleAnywhere)TObjectPtr<UProjectileMovementComponent> ProjectileMovement;protected:// Called when the game starts or when spawnedvirtual 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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/643567.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于小程序实现的查寝打卡系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

Golang | Leetcode Golang题解之第46题全排列

题目&#xff1a; 题解&#xff1a; func permute(nums []int) [][]int {var (n len(nums)dfs func(vals []int) // 已选择数 排列为vals 后续回溯继续选择 直至选完ans [][]int)dfs func(vals []int) {//边界if len(vals) n {ans append(ans, vals)}//转移 枚举选哪个f…

项目实战 | 责任链模式 (下)

案例二&#xff1a;工作流&#xff0c;费用报销审核流程 同事小贾最近刚出差回来&#xff0c;她迫不及待的就提交了费用报销的流程。根据金额不同&#xff0c;分为以下几种审核流程。报销金额低于1000元&#xff0c;三级部门管理者审批即可&#xff0c;1000到5000元除了三级部…

如何从架构层面降低公有云多可用区同时故障的概率

阿里云和腾讯云都曾出现过因一个组件故障而导致所有可用区同时瘫痪的情况。本文将探讨如何从架构设计的角度减小故障域&#xff0c;在故障发生时最小化业务损失&#xff0c;并以 Sealos 的稳定性实践为例&#xff0c;分享经验教训。 抛弃主从&#xff0c;拥抱点对点架构 从腾…

第26天:安全开发-PHP应用模版引用Smarty渲染MVC模型数据联动RCE安全

第二十六天 一、PHP新闻显示-数据库操作读取显示 1.新闻列表 数据库创建新闻存储代码连接数据库读取页面进行自定义显示 二、PHP模版引用-自写模版&Smarty渲染 1.自写模版引用 页面显示样式编排显示数据插入页面引用模版调用触发 2.Smarty模版引用 1.下载&#xff1a…

小程序 rich-text 解析富文本 图片过大时如何自适应?

在微信小程序中&#xff0c;用rich-text 解析后端返回的数据&#xff0c;当图片尺寸太大时&#xff0c;会溢出屏幕&#xff0c;导致横向出现滚动 查看富文本代码 图片是用 <img 标签&#xff0c;所以写个正则匹配一下图片标签&#xff0c;手动加上样式即可 // content 为后…

iOS ------代理 分类 拓展

代理协议 一&#xff0c;概念&#xff1a; 代理&#xff0c;又称委托代理&#xff08;delegate&#xff09;&#xff0c;是iOS中常用的一种设计模式。顾名思义&#xff0c;它是把某个对象要做的事委托给别的对象去做。那么别的对象就是这个对象的代理&#xff0c;代替它来打理…

构建NodeJS库--前端项目的打包发布

1. 前言 学习如何打包发布前端项目&#xff0c;需要学习以下相关知识&#xff1a; package.json 如何初始化配置&#xff0c;以及学习npm配置项&#xff1b; 模块类型type配置&#xff0c; 这是nodejs的package.json的配置main 入口文件的配置 webpack 是一个用于现代 JavaSc…

Python程序设计教案

文章目录&#xff1a; 一&#xff1a;软件环境安装 1.软件环境 2.技巧 3.新建工程项目 二&#xff1a;相关 1.规范 2.关键字 3.Ascll码表 三&#xff1a;语法基础 1.各种符号 1.1 注释 1.2 占位置的 1.3 回车换行 2.输入输出 2.1 输入input 2.2 输出print …

每天五分钟计算机视觉:基于YOLO算法精确分类定位图片中的对象

滑动窗口的卷积的问题 滑动窗口的卷积实现效率很高,但是它依然不能够输出最精准的边界框,比如下面所示: 我们可以看到蓝色框不论在什么位置都不能很好的确定车的位置,有一个算法是YOLO 算法它能够帮助我们解决这个问题。 YOLO 算法 比如我们的输入图像是100*100,我们会…

如何理解自然语言处理中的位置编码(Positional Encoding)

在自然语言处理和特别是在使用Transformer模型中,位置编码(Positional Encoding)是一个关键的概念。它们的作用是为模型提供序列中各个元素的位置信息。由于Transformer架构本身并不像循环神经网络(RNN)那样具有处理序列的固有能力,位置编码因此显得尤为重要。 为什么需…

【webrtc】Chrome和Firefox在SDP协商过程中,针对localhost的不同处理

内网下chrome端webrtc协商失败 现象 我有一个webrtc服务器在局域网内&#xff0c;使用chrome浏览器访问时&#xff0c;发现webrtc在做媒体协商时失败。 具体表现是&#xff0c;在交换sdp后&#xff0c;ice的状态是oniceconnectionstatechange: failed 但是换成Firefox浏览器…