【UE5.3 C++】ARPG游戏 05-准备角色攻击的武器和动画

目录

步骤

一、创建Item类

[1.1 上下浮动效果](#1.1 上下浮动效果)

[1.2 拥有碰撞检测](#1.2 拥有碰撞检测)

[1.3 拥有静态网格体组件](#1.3 拥有静态网格体组件)

二、创建Weapon类

三、附加Actor到Sockets

四、准备角色动画

[4.1 下载动画资源](#4.1 下载动画资源)

[4.2 动画重定向](#4.2 动画重定向)

[4.2.1 创建Mixamo的IK绑定](#4.2.1 创建Mixamo的IK绑定)

[4.2.2 创建Echo的IK绑定](#4.2.2 创建Echo的IK绑定)

[4.2.3 创建IK重定向器](#4.2.3 创建IK重定向器)


效果

步骤

一、创建Item类

Item类派生自Actor类,该类主要作用是可以上下浮动、拥有碰撞检测以及拥有静态网格体组件。

首先在该类中实现上下浮动的功能,这里根据公式的规律来让item在Z轴方向上下运动。因此这里在"Item.h"中定义如下3个变量和1个函数,Amplitude为公式中的A(振幅),RunningTime为公式中的t。InitialLocation表示item的初始位置。TransformedSin()用于得出公式中的z值。

1.1 上下浮动效果

InitialLocation通过在BeginPlay中获取1次item的初始位置

在"Item.cpp"中每帧更新当前运行时间"RunningTime",TransformedSin输出初始Z坐标加上正弦函数值

在蓝图中只需要每帧设置item的位置就可以实现上下浮动效果

1.2 拥有碰撞检测

为了实现碰撞检测,这里先在"Item.h"中定义球形碰撞组件

在"Item.cpp"构造函数中创建球形碰撞组件,注意需先引入头文件:

#include "Components/SphereComponent.h"

定义OnSphereOverlap和OnSphereEndOverlap函数,表示有物体接触和离开item碰撞检测区域后要做的事。使用virtual关键字是为了在子类Weapon中重写这两个函数。

在BeginPlay中设置物体接触和离开item时的委托函数分别为OnSphereOverlap和OnSphereEndOverlap

这里可以先不实现有物体接触和离开item碰撞检测区域后要做的事,等在继承Item类的Weapon类中再具体实现

1.3 拥有静态网格体组件

在"Item.h"中声明静态网格体组件ItemMesh

构造函数中创建组件

二、创建Weapon类

在Quixel Bridge中添加一把剑的资产

添加后项目浏览器包含如下资产

新建Weapon类继承自Item类

代码创建好后,再创建一个基于Weapon的蓝图类

这里命名为"BP_Weapon"

打开"BP_Weapon",设置静态网格体,并修改球形碰撞区域半径以适应网格体大小

为了让剑产生上下浮动效果,需要在蓝图中添加如下节点

在"Weapon.h"中申明重写父类的OnSphereOverlap和OnSphereEndOverlap函数

三、附加Actor到Sockets

现有有了剑,接下来要解决的问题是如何让剑握在角色手里,这里用到的是scokets,可以用来将actor添加到骨骼网格体的骨骼上。

找打角色的骨骼网格体并打开

鼠标点击hand_r,点击添加插槽

这里命名为"RightHandSocket"

添加预览资产为剑

可以看到此时的Socket位置和方向不对,需要调整

如下图是调整后的socket位置和旋转

在"预览场景设置"中可以预览角色播放动画时的姿势

四、准备角色动画

4.1 下载动画资源

访问Mixamo,由于Mixamo动画不能直接用在我们的角色上,因此先下载Mixamo角色"XBot"

将下载后的.fbx文件导入UEEditor,直接点击"导入所有"

导入后文件如下

在Mixamo中下载动画资源,这里先下载持剑站立和攻击的动画

导入后只保留如下动画序列资产

4.2 动画重定向

4.2.1 创建Mixamo的IK绑定

新建"IK绑定"

这里命名为"IKRig_XBot"

打开"IKRig_XBot",预览骨骼网格体选择"XBot"

右键点击"Hips",设置其为重定向根

右键点击"Hips",选择"新建重定向链"

链名称设置为"Root",然后点击"添加链"

选中脊柱的三个骨骼,选择"新建重定向链"

同样的,选择脖子和头建立链条

选中"RightShoulder"新建链条

这里命名链条为"RightClavicle"

选中"LeftShoulder",新建链条

这里命名为"LeftClavicle"

选择右臂三根骨骼,新建链条,命名为"RightArm"

选择左臂三根骨骼,新建链条,命名为"LeftArm"

选择左右手拇指新建链条

左右手食指

左右手中指

左右手无名指

左右手小指

左右腿

现在我们有了Mixamo骨骼上所有IK绑定的链条,接下来创建我们的角色"Echo"的IK绑定

4.2.2 创建Echo的IK绑定

新建一个IK绑定,这里命名为"IKRig_Echo"

打开"IKRig_Echo",预览骨骼网格体设置为"Echo"

接下来只需要创建与"IKRig_XBot"那些链条相对应的链条即可。首先设置骨骼"pelvis"为重定向根。

选择Root骨骼,新建重定向链,这里链名称同样设置为"Root"

建立脊椎链,注意链条名称要和"IKRig_XBot"中的链条名称保持一致,这样UE才能对应上。

头部链条

左右锁骨

左右手臂

左右手食指

左右手中指

左右手小指

左右手无名指

左右手拇指

左右腿

4.2.3 创建IK重定向器

创建一个IK重定向器

这里命名为"RTG_XBot"

打开"RTG_XBot",设置源IKRig资产为"IKRig_XBot",设置目标IKRig资产为"IKRig_Echo"

为了方便观察,设置目标网格体偏移为150

新建一个重定向姿势,这里命名为"ToEcho"

点击编辑"重定向姿势"

调整手臂、腿部姿势,尽量保证和Mixamo角色姿势一致

注意在俯视角中看到手臂也不是直的,需要调整

再调整一下手掌

调整好后可以预览动画观察动作是否正常

选中要重定向的动画,然后点击"导出选定动画"

导出动画序列如下

打开动画序列,可以再调整一下socket的位置

代码

(1) Item类

cpp 复制代码
// Item.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Item.generated.h"

UCLASS()
class SLASH_API AItem : public AActor
{
	GENERATED_BODY()
	
public:	
	AItem();
	virtual void Tick(float DeltaTime) override;

protected:
	virtual void BeginPlay() override;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Sine Parameters")
	float Amplitude = 30.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Sine Parameters")
	float RunningTime;

	UPROPERTY(EditAnywhere, BlueprintReadOnly)
	FVector InitialLocation;

	UFUNCTION(BlueprintPure)
	float TransformedSin();

	UFUNCTION()
	virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	virtual void OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

private:
	UPROPERTY(VisibleAnywhere)
	UStaticMeshComponent* ItemMesh;

	UPROPERTY(VisibleAnywhere)
	class USphereComponent* Sphere;
};
cpp 复制代码
// Item.cpp


#include "Items/Item.h"
#include "Slash/DebugMacros.h"
#include "Components/SphereComponent.h"


AItem::AItem()
{
	PrimaryActorTick.bCanEverTick = true;

	ItemMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ItemMeshComponent"));
	RootComponent = ItemMesh;

	Sphere = CreateDefaultSubobject<USphereComponent>(TEXT("Sphere"));
	Sphere->SetupAttachment(RootComponent);
}

void AItem::BeginPlay()
{
	Super::BeginPlay();
	InitialLocation = GetActorLocation();

	Sphere->OnComponentBeginOverlap.AddDynamic(this, &AItem::OnSphereOverlap);
	Sphere->OnComponentEndOverlap.AddDynamic(this, &AItem::OnSphereEndOverlap);
}

void AItem::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	RunningTime += DeltaTime;
}

float AItem::TransformedSin()
{
	return InitialLocation.Z + Amplitude * FMath::Sin(RunningTime * 5.f);
}

void AItem::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	const FString OtherActorName = OtherActor->GetName();
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(1, 5.f, FColor::Red, OtherActorName);
	}
}

void AItem::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	const FString OtherActorName = FString("Ending Overlap with: ") + OtherActor->GetName();
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(1, 5.f, FColor::Blue, OtherActorName);
	}
}

(2)Weapon类

cpp 复制代码
// Weapon.h

#pragma once

#include "CoreMinimal.h"
#include "Items/Item.h"
#include "Weapon.generated.h"

/**
 * 
 */
UCLASS()
class SLASH_API AWeapon : public AItem
{
	GENERATED_BODY()

protected:
	virtual void OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) override;
	virtual void OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) override;

};
cpp 复制代码
// Weapon.cpp


#include "Items/Weapons/Weapon.h"

void AWeapon::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	Super::OnSphereOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult);
}

void AWeapon::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	Super::OnSphereEndOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex);
}
相关推荐
GOSIM 全球开源创新汇12 小时前
科班出身+跨界双轨:陈郑豪用 AI 压缩技术,让 4K 游戏走进普通设备|Open AGI Forum
人工智能·游戏·agi
zhangzhangkeji12 小时前
UE5 C++(15-3):UFUNCTION 的 meta 元数据, DisplayName ,同 UPROPERTY 的 meta
ue5
夜色。15 小时前
UE5 Error LNK2019 编译异常修复备忘
ue5
幽络源小助理16 小时前
逆向工程系统学习资源图谱(2026):从 Windows 内核、安卓安全到游戏协议分析的全栈教程清单
学习·安全·游戏·逆向工程
陈友松1 天前
UE5 表格文件动态导入导出插件
ue5
zhangzhangkeji1 天前
UE5 C++(17):结构体,USTRUCT(BlueprintType) struct FmyStruct ,必须用 F 开头
ue5
i橡皮擦1 天前
TheIsle恐龙岛游戏管理员命令
游戏·恐龙岛·theisle
zhutoutoutousan2 天前
氛围数学学习:用游戏化思维征服抽象数学
学习·算法·游戏
碎梦人2 天前
基于UE5开发的pico大空间项目开发之虚拟坐标系与真实坐标系的对应关系
ue5·lbe·大空间坐标系对应关系