5. UE5 RPG使用GAS技能系统

86 篇文章 11 订阅

之前也介绍过GAS的使用:
UE 5 GAS Gameplay Ability System
UE 5 GAS 在项目中处理AttributeSet相关
UE 5 GAS 在项目中通过数据初始化
基础的讲解这里不再诉说,有兴趣的可以翻我之前的博客。

接下来,在RPG游戏中实现GAS系统的使用。
GAS系统可以放到角色Pawn身上,也可以放到PlayerState里面,如果放到Pawn身上,GAS也会跟着销毁,这个比较方便与敌人身上,所以敌人的Ability System Component(ASC)和Attribute Set我们将直接放置到敌人的Pawn身上,而玩家控制的角色,牵扯到一个复活的问题,我们需要保存技能相关的数据,将放置到PlayerState身上,那样如果销毁掉角色Pawn,相关数据也会保存下来。

创建PlayerState

首先点击创建c++类,创建一个玩家状态类 PlayerState
在这里插入图片描述
设置名称
在这里插入图片描述
创建完成后再PlayerState.cpp中初始化时,修改NetUpdateFrequency 默认为2,使用了GAS可以设置的更高

// 版权归暮志未晚所有。


#include "Player/PlayerStateBase.h"

APlayerStateBase::APlayerStateBase()
{
	NetUpdateFrequency = 100.f; //每秒和服务器更新频率,使用GAS后可以设置的高一些
}

打开ue,创建对应的蓝图类
在这里插入图片描述
放置到蓝图文件夹内
在这里插入图片描述
将GameMode里面的玩家状态类修改成当前创建的蓝图。
在这里插入图片描述
上面提到了,推荐将玩家的GAS存储在playerState里面,这里我们先创建玩家状态类供后面使用。

添加GAS

打开插件,搜素gameplay,找到gameplay Abilities,添加,重新启动。
在这里插入图片描述
添加新的c++类,父类为AbilitySystemComponent
在这里插入图片描述
创建ASC基类
在这里插入图片描述
接下来创建数据集类,父类为AttributeSet
在这里插入图片描述
在私有模块中添加相关模块

PrivateDependencyModuleNames.AddRange(new string[] { "GameplayAbilities", "GameplayTags", "GameplayTasks" });

代码中添加

带有ASC的Actor也被称为ASC的OwnerActor。ASC实际作用的Actor叫作AvatarActor。OwnerActor和AvatarActor可以是同一个Actor,比如MOBA游戏中的野怪。它们也可以是不同的 Actors,比如MOBA游戏中玩家和AI控制的英雄角色,OwnerActor是PlayerState、AvatarActor是HeroCharacter。大部分情况下OwnerActor和AvatarActor可以是角色Actor。不过想像一下你控制的英雄角色死亡然后重生的过程,如果此时要保留死亡前的Attributes或者GameplayEffects,那么最理想的做法是将ASC交给PlayerState。

如果OwnerActor和AvatarActor是不同的Actors,那么两者都需要实现IAbilitySystemInterface, 方便用于获取GAS的数据。这个接口只有一个方法需要被重载UAbilitySystemComponent* GetAbilitySystemComponent() const,此方法将返回ASC。

接下来将实现在Character和playerState上面实现GAS的添加,主要添加的内容为两项:AbilitySystemComponent(ASC)和AttributeSet(AS)

首先实现在角色类里面添加,我们在类里面创建两个属性,分别用来定义ASC和AS,记得声明它们的类。主角类和敌人基础的类都会继承角色基础类,那么,它们都会创建相关的属性。
在这里插入图片描述
敌人的OwnerActor和AvatarActor是相同的,我们直接在敌人的基类的构造函数里面对ASC和AS实例化。

AEnemyBase::AEnemyBase()
{
	GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); //设置可视为阻挡

	AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");
	AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制

	AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
}

主角的组件和数据,我们首先需要先在PlayerState身上设置,然后在characterBase身上去引用PlayerState身上的对应组件和数据,这样,即使character销毁掉,创建新的,我们一样可以获取到修改后的数据。
所以,我们在playerState身上也需要创建对应的ASC和AS
在这里插入图片描述
角色的直接在PlayerState构造函数里实例化

// 版权归暮志未晚所有。


#include "Player/PlayerStateBase.h"
#include "AbilitySystem/AbilitySystemComponentBase.h"
#include "AbilitySystem/AttributeSetBase.h"

APlayerStateBase::APlayerStateBase()
{
	NetUpdateFrequency = 100.f; //每秒和服务器更新频率,使用GAS后可以设置的高一些
	
	AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");
	AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制

	AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
}

接下来比较重要的一步就是,如何在Character里面去获取PlayerState的技能组件,这里我们使用了GAS组件自带AbilitySystemInterface接口去实现。
需要在.h文件中使用技能组件,所以,我们将模块移入到Public列表中。
在这里插入图片描述
在playerState里,继承接口,实现接口的虚函数,用于获取ASC,并实现获取AS的函数。

// 版权归暮志未晚所有。

#pragma once

#include "CoreMinimal.h"
#include "AbilitySystemInterface.h"
#include "GameFramework/PlayerState.h"
#include "PlayerStateBase.generated.h"

class UAbilitySystemComponent;
class UAttributeSet;
/**
 * 
 */
UCLASS()
class AURA_API APlayerStateBase : public APlayerState, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	APlayerStateBase();
	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; //覆盖虚函数获取asc
	UAttributeSet* GetAttributeSet() const { return AttributeSet; } //获取as

protected:
	
	UPROPERTY()
	TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

	UPROPERTY()
	TObjectPtr<UAttributeSet> AttributeSet;
};

cpp里定义也只是返回asc组件。

UAbilitySystemComponent* APlayerStateBase::GetAbilitySystemComponent() const
{
	return AbilitySystemComponent;
}

这样,玩家的ASC和AS可以通过接口去获取ASC以及定义的函数获取AS
character同样继承此接口,并实现对应的函数。
在这里插入图片描述
玩家的playerState和character里面存储的ASC和AS需要相同,我们可以在初始化玩家Character的时候,从PlayerState里获取ASC和AS

void AHeroCharacter::InitAbilityActorInfo()
{
	APlayerStateBase* PlayerStateBase = GetPlayerState<APlayerStateBase>();
	check(PlayerStateBase);
	//从playerState获取ASC和AS
	AbilitySystemComponent = PlayerStateBase->GetAbilitySystemComponent();
	AttributeSet = PlayerStateBase->GetAttributeSet();
}

接下来我们要设置复制模式,以便来同步客户端和服务器端数据。
在这里插入图片描述
在角色的asc上面,我们使用Mixed模式同步。

APlayerStateBase::APlayerStateBase()
{
	AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");
	AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制
	AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);

	AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
	
	NetUpdateFrequency = 100.f; //每秒和服务器更新频率,使用GAS后可以设置的高一些
}

而怪物的asc,则使用Minimal模式

AEnemyBase::AEnemyBase()
{
	GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); //设置可视为阻挡

	AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");
	AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制
	AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal);

	AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
}

初始化AbilitySysytemComponent

ASC需要有OwnerActor和AvatarActor进行初始化,而且必须在服务器和客户端都要完成初始化。

对于玩家控制的角色,ASC存在于Pawn中,我通常在Pawn的 PossessedBy()方法中完成ASC在服务器端的初始化,在PlayerController的AcknowledgePawn()方法中完成ASC在客户端的初始化。

对于玩家控制的角色,ASC存在于PlayerState中,我通常在Pawn 的PossessedBy() 方法中完成ASC在服务器端的初始化(这一点与上述相同),在 Pawn的 OnRep_PlayerState()方法中完成ASC在客户端的初始化(这将确保PlayerState在客户端已存在)。

初始化AI角色的GAS

对于AI控制的角色,ASC存在于Pawn中,通常在Pawn的 BeginPlay()方法中完成ASC在服务器端和客户端的初始化。

既然根据文档知道了如何初始化,那么,我们按照相应的方式初始化。首先初始化敌人身上的ASC,敌人作为ai怪物,只需要在BeginPlay里面初始化即可。

首先覆盖BeginPlay()的函数
在这里插入图片描述
然后在BeginPlay()里面调用InitAbilityActorInfo初始化即可完成。

void AEnemyBase::BeginPlay()
{
	Super::BeginPlay();

	AbilitySystemComponent->InitAbilityActorInfo(this, this);
}

初始化玩家角色GAS

接下来是玩家控制角色的ASC初始化,玩家控制角色按照文档说法,我们需要在AvatarActor里面进行初始化。
如果ASC存在于PlayerState中,我需要在AvatarActor覆盖PossessedBy和OnRep_PlayerState两个函数,然后添加私有初始化函数InitAbilityActorInfo(初始化的内容相同)
在这里插入图片描述
初始化函数AbilitySystemComponent->InitAbilityActorInfo需要指定两个值:OwnerActor和AvatarActor。
前面我们在Character设置ASC和AS时,就已经获取到了PlayerState,现在只需要调用InitAbilityActorInfo传入参数即可。

void AHeroCharacter::InitAbilityActorInfo()
{
	APlayerStateBase* PlayerStateBase = GetPlayerState<APlayerStateBase>();
	check(PlayerStateBase);
	//从playerState获取ASC和AS
	AbilitySystemComponent = PlayerStateBase->GetAbilitySystemComponent();
	AttributeSet = PlayerStateBase->GetAttributeSet();
	//初始化ASC
	AbilitySystemComponent->InitAbilityActorInfo(PlayerStateBase, this);
}

然后在PossessedBy()和OnRep_PlayerState()调用AHeroCharacter::InitAbilityActorInfo(),完成服务端和客户端的初始化。

void AHeroCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	//初始化ASC的OwnerActor和AvatarActor
	InitAbilityActorInfo();
}

void AHeroCharacter::OnRep_PlayerState()
{
	Super::OnRep_PlayerState();

	//初始化ASC的OwnerActor和AvatarActor
	InitAbilityActorInfo();
}

注意: Mixed 复制模式要求OwnerActor的 Owner必须是Controller。 PlayerState的 Owner默认是Controller,但是Character不是。如果使用Mixed复制模式的OwnerActor不是PlayerState那么你需要在OwnerActor上调用SetOwner()并传递一个有效的Controller。(不过从4.24开始, PossessedBy() 会为Pawn设置一个新的Controller。)

void AHeroCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	//初始化ASC的OwnerActor和AvatarActor
	InitAbilityActorInfo();

	//设置OwnerActor的Controller
	SetOwner(NewController);
}

参考:虚幻引擎游戏技能系统文档

  • 28
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Unreal Engine 5 (UE5)中实现合成系统可以通过以下步骤完成: 1. 创建一个Actor类,作为合成系统的基础。可以使用UE5自带的Actor类或者自定义一个Actor类。 2. 在Actor类中添加必要的变量和函数,例如合成的输入和输出物品、合成的材料、合成的效果等。 3. 创建一个UI界面,用于显示和控制合成系统。可以使用UE5自带的UMG或者其他UI框架来创建。 4. 在UI界面中添加按钮和其他控件,用于控制合成系统。例如,添加一个合成按钮,当用户点击该按钮时,合成系统将进行合成操作。 5. 在合成系统的函数中实现合成的逻辑。根据输入的材料和合成的效果,计算出合成的结果,并将结果输出到指定的位置。 6. 在UE5中创建一些测试场景,用于测试合成系统的功能和性能。 下面是一个简单的例子,演示如何使用UE5实现一个合成系统: 1. 创建一个Actor类,名为CraftingSystem。 2. 在CraftingSystem中添加以下变量和函数: ```c++ UPROPERTY(EditAnywhere) UStaticMeshComponent* OutputItemMesh; // 合成的输出物品 UPROPERTY(EditAnywhere) TArray<TSubclassOf<AActor>> InputItemClasses; // 合成的输入物品 UPROPERTY(EditAnywhere) TArray<int32> InputItemCounts; // 合成的输入物品数量 UPROPERTY(EditAnywhere) TSubclassOf<AActor> CraftEffectClass; // 合成的效果 UFUNCTION(BlueprintCallable) void Craft(); // 合成的函数 ``` 3. 创建一个UI界面,名为CraftingUI。 4. 在CraftingUI中添加一个合成按钮。 5. 在CraftingUI中为合成按钮添加点击事件,调用CraftingSystem的Craft函数。 6. 在CraftingSystem的Craft函数中实现合成的逻辑。计算出需要的输入物品和数量,如果输入物品足够,将其减少并生成一个输出物品和一个合成效果。 ```c++ void ACraftingSystem::Craft() { TArray<AActor*> inputItems; for (int32 i = 0; i < InputItemClasses.Num(); i++) { UClass* inputClass = InputItemClasses[i]; int32 inputCount = InputItemCounts[i]; TArray<AActor*> foundActors; UGameplayStatics::GetAllActorsOfClass(GetWorld(), inputClass, foundActors); int32 count = 0; for (AActor* actor : foundActors) { if (count >= inputCount) { break; } if (inputItems.Contains(actor)) { continue; } inputItems.Add(actor); count++; } if (count < inputCount) { UE_LOG(LogTemp, Error, TEXT("Not enough input items.")); return; } } for (AActor* actor : inputItems) { actor->Destroy(); } AActor* outputItem = GetWorld()->SpawnActor<AActor>(OutputItemClass
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值