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

news2024/10/7 6:46:57

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

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

添加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 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();
}





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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Prompt Engineering,提示工程

什么是提示工程&#xff1f; 提示工程也叫【指令工程】。 Prompt发送给大模型的指令。比如[讲个笑话]、[用Python编个贪吃蛇游戏]、[给男/女朋友写情书]等看起来简单&#xff0c;但上手简单精通难 [Propmpt]是AGI时代的[编程语言][Propmpt]是AGI时代的[软件工程][提示工程]是…

ROS 话题订阅模型之自定义消息类型 C++实现

ROS 话题订阅模型之自定义消息类型 1.自定义消息类型好处 ROS提供了许多标准的消息类型&#xff0c;如 std_msgs/String、sensor_msgs/Image 等&#xff0c;涵盖了很多常见的数据类型和传感器数据。但是&#xff0c;在实际的开发中&#xff0c;我们经常会遇到需要传输的数据类…

云计算中的过度授权:安全隐患与应对策略

云计算凭借其弹性、可扩展等优势&#xff0c;已经成为诸多企业组织拓展业务的重要基础设施之一。然而&#xff0c;与传统IT架构相比&#xff0c;云计算环境的安全管理也面临着新的挑战。过度授权 (Overprivileging) 便是云安全领域亟待解决的主要问题之一&#xff0c;本文将带领…

CPPTest实例分析(C++ Test)

1 概述 CppTest是一个可移植、功能强大但简单的单元测试框架&#xff0c;用于处理C中的自动化测试。重点在于可用性和可扩展性。支持多种输出格式&#xff0c;并且可以轻松添加新的输出格式。 CppTest下载地址&#xff1a;下载地址1  下载地址2 下面结合实例分析下CppTest如…

【Linux】解决ubuntu20.04版本插入无线网卡没有wifi显示【无线网卡Realtek 8811cu】

ubuntu为Realtek 8811cu安装驱动&#xff0c;解决wifi连接问题 1、确认无线网卡的型号-Realtek 8810cu2、下载并配置驱动 一句话总结&#xff1a;先确定网卡的型号&#xff0c;然后根据网卡的型号区寻找对应的驱动下载&#xff0c;下载完成之后在ubuntu系统中进行编译&#xff…

【STM32+HAL+Proteus】系列学习教程4---GPIO输入模式(独立按键)

实现目标 1、掌握GPIO 输入模式控制 2、学会STM32CubeMX配置GPIO的输入模式 3、具体目标&#xff1a;1、按键K1按下&#xff0c;LED1点亮&#xff1b;2、按键K2按下&#xff0c;LED1熄灭&#xff1b;2、按键K3按下&#xff0c;LED2状态取反&#xff1b; 一、STM32 GPIO 输入…

C语言 字符类型

下面 我们来说字符类型 我们来看这个 保险单 金额 和 总额 都可以用数字类型 而性别则需要字符型 字符数据的存储 – ASCI码 字符类型 char 就是专为存储字符(如字母&#xff0c;标点和数字)而设计的类型。 使用单引号包含单个字符或转义字符去表示一个 char 类型的常量。 …

mac电脑搭建vue环境(上篇)

第一步&#xff1a;mac电脑要有homebrew&#xff0c;如何安装homebrew 点击下方 MAC安装homebrew-CSDN博客 第二步&#xff1a;homebrew安装node.js 第三步&#xff1a;安装npm 第四步&#xff1a;安装webpack 第五步&#xff1a;安装vue脚手架 第六步&#xff1a;可以在…

解决双击PDF文件出现打印的问题【Adobe DC】

问题描述 电脑安装Adobe Acrobat DC之后&#xff0c;双击PDF文件就会出现打印&#xff0c;而无法直接打开。 右键PDF文件就会发现&#xff0c;第一栏出现的不是用Adobe打开&#xff0c;而是打印。 重装软件多次仍然无法解决。 原因 右键菜单被改写了。双击其实是执行右键菜…

idea上传项目到gitee(码云)

1、打开码云&#xff0c;新建仓库 2、创建 3、这就是创建成功的页面 4、复制仓库地址&#xff0c;后面需要用到 2、打开我们的项目&#xff1a;例如我现在的项目 1、idea创建git仓库 2、选择我们项目文件夹的目录 3、查看文件是否变色&#xff0c;变色表示成功了 4、添加到缓…

Amazon云计算AWS之[2]弹性计算云EC2

文章目录 说明EC2基本架构Amazon机器映象&#xff08;AMI&#xff09;实例&#xff08;Instance&#xff09;弹性块存储&#xff08;EBS&#xff09; EC2关键技术地理区域和可用区域EC2通信机制弹性负载均衡监控服务自动缩放服务管理控制台 EC2安全及容错机制EC2弹性IP地址 说明…

网盘——查看文件

本文主要讲解文件操作过程中&#xff0c;查看文件如何实现&#xff0c;实现步骤如下&#xff1a; 1、实现步骤&#xff1a; A、首先客户端发送查看请求&#xff08;包含目录信息&#xff09; B、服务器将文件名字还有文件的类型发送给客户端&#xff08;只发送文件的名字&am…

FebHost:科技企业如何规划并注册.AI域名?

为确保企业使用.AI域名的方式准确反映其对人工智能技术的关注&#xff0c;企业应考虑以下步骤&#xff1a; 了解法律和合规要求&#xff1a; 第一步是了解与 .AI 域名相关的独特法律和合规要求。由于.AI域名源于安圭拉&#xff0c;企业必须遵守安圭拉的限制和法律规定。这包括…

简单谈谈URL过滤在网络安全中的作用

用户花在网络上的时间越来越多&#xff0c;浏览他们最喜欢的网站&#xff0c;点击电子邮件链接&#xff0c;或利用各种基于网络的 SaaS 应用程序供个人和企业使用。虽然这种不受约束的网络活动对提高企业生产力非常有用&#xff0c;但也会使组织面临一系列安全和业务风险&#…

学习Rust第14天:HashMaps

今天我们来看看Rust中的hashmaps&#xff0c;在 std::collections crate中可用&#xff0c;是存储键值对的有效数据结构。本文介绍了创建、插入、访问、更新和迭代散列表等基本操作。通过一个计算单词出现次数的实际例子&#xff0c;我们展示了它们在现实世界中的实用性。Hashm…

笔记本电脑耗电和发热比较厉害怎么处理

工作中会遇到有同事反馈笔记本电脑耗电和发热比较厉害&#xff0c;主要检查以下几个地方 1、CPU频率 很多人觉得是cpu使用率高就代表电脑跑得快&#xff0c;发热量就大&#xff0c;其实不是的&#xff0c;主要是看的cpu频率&#xff0c;频率越高&#xff0c;电脑发热量越大。如…

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-GRU-SAM-Attention卷积门控循环单元融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现CNN-GRU…

关于Java的三个小题目(很容易错!)

第一题 char运算后的数据类型 最后输出的是什么类型&#xff1f; 答案&#xff1a;int char与byte的联系和区别 char是无符号型的&#xff0c;能够表示一个整数&#xff0c;不能表示负数&#xff08;0~65535&#xff09;&#xff1b;而byte是有符号型的&#xff0c;能够表示…

AI视频改字个性化祝福豪车装X系统uniapp前端开源源码下载

装X系统源码简介 创意无限&#xff01;AI视频改字祝福&#xff0c;豪车装X系统源码开源&#xff0c;打造个性化祝福视频不再难&#xff01; 想要为你的朋友或家人送上一份特别的祝福&#xff0c;让他们感受到你的真诚与关怀吗&#xff1f;现在&#xff0c; 通过开源的AI视频…

fnm:Rust开发的高效Node版本管理工具

简介 fnm 是一个基于 Rust 开发的 Node 版本管理工具&#xff0c;它的目标是提供一个快速、简单且可靠的方式来管理 Node.js 的不同版本。同时&#xff0c;它是跨平台的&#xff0c;支持 macOS、Linux、Windows。&#x1f680; Fast and simple Node.js version manager, buil…