在正常的游戏中,我们应该考虑如何去初始化角色属性,并且要给角色分好类型。比如,在我们游戏中,我们如何去初始化小兵的属性,并且还要实现小兵随着等级的增长而增加属性。而且就是小兵也有类型的区分,比如我们将在后面设置小兵分为三种:战士,游侠,法师。而小兵的属性实现,一般需要策划进行配表实现,将小兵的属性统一性的存入到表格导入项目。
我们将使用枚举去定义敌人的类型并创建一个ECharacterClass,并创建一个DataAsset命名为UCharacterClassInfo用来设置每种类型使用的属性初始化的GE。对于随着等级变动的基础属性,我们将使用曲线表格去生成所有等级的数据。并且,在数据中,我们去设置敌人需要附带的技能。
所以,接下来,我们实现的步骤是:
- 创建DataAsset储存UCharacterClassInfo
// YanWei.
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "CharacterClassInfo.generated.h"
class UGameplayEffect;
//角色职业类型的枚举
UENUM(BlueprintType)
enum class ECharacterClass : uint8
{
Elementalist, //法师
Warrior, //战士
Ranger //游侠
};
USTRUCT()
struct FCharacterClassDefaultInfo
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, Category="Class Defaults")
TSubclassOf<UGameplayEffect> PrimaryAttributes;
};
/**
* 根据职业选择初始化角色的数据
*/
UCLASS()
class AURA_API UCharacterClassInfo : public UDataAsset
{
GENERATED_BODY()
public:
//用于根据不同的职业选择不同的结构体,
UPROPERTY(EditDefaultsOnly, Category="Class Defaults")
TMap<ECharacterClass, FCharacterClassDefaultInfo> CharacterClassInformation;
UPROPERTY(EditDefaultsOnly, Category="Common Class Defaults")
TSubclassOf<UGameplayEffect> SecondaryAttributes;
UPROPERTY(EditDefaultsOnly, Category="Common Class Defaults")
TSubclassOf<UGameplayEffect> VitalAttributes;
//通过枚举获取对应的初始化类
FCharacterClassDefaultInfo GetClassDefaultInfo(ECharacterClass CharacterClass);
};
// YanWei.
#include "AbilitySystem/Data/CharacterClassInfo.h"
FCharacterClassDefaultInfo UCharacterClassInfo::GetClassDefaultInfo(ECharacterClass CharacterClass)
{
return CharacterClassInformation.FindChecked(CharacterClass);
}
2. 创建GE去填充DA_CharacterInfo
3.创建GE使用的 CurveTable
依次是 常数 线性 立方体(平滑曲线)
操作流程 添加n个关键帧->三次插值自动切线
4.CurveTable 填入GE
还有另外两种方法 CSV 和 JSON
- 现在通过设置好的通用GE去实例化Enemy
创建完成对应的GE,我们并使用数据表格填充了对应的数据,接下来,我们将通过代码实现对应的逻辑去初始化角色。
首先,我们考虑将创建数据放在哪里,这里我们将其放到GameMode上面,对于GameMode来说,在不同场景可以设置不同的GameMode,刚好合适,比如你创建了一个关卡,可以设置上对应的数据,关卡内的敌人初始化时,就使用这一套GE去初始化。
在我们的GameMode基类上增加一个变量,用于设置数据 蓝图中设置CharacterClassInofo(DataAsset)
在函数库增加一个函数,用于初始角色属性
//函数的实现
void UMyASBlueprintFunctionLibrary::InitializeDefaultAttributes(const UObject* WorldContextObject,
ECharacterClass CharacterClass, float Level, UAbilitySystemComponent* ASC)
{
//这里需要用到ASC去索引到AvatarActor 才能应用GE属性
AActor* AvatarActor = ASC->GetAvatarActor();
//获取到当前关卡的GameMode实例
const AAuraGameModeBase* GameMode = Cast<AAuraGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject));
if(GameMode == nullptr) return;
//从实例获取到关卡角色的配置
UCharacterClassInfo* ClassInfo = GameMode->CharacterClassInfo;
//获取到默认的基础角色数据
const FCharacterClassDefaultInfo ClassDefaultInfo = ClassInfo->GetClassDefaultInfo(CharacterClass);
//应用基础属性
FGameplayEffectContextHandle PrimaryContextHandle = ASC->MakeEffectContext();
PrimaryContextHandle.AddSourceObject(AvatarActor);
const FGameplayEffectSpecHandle PrimarySpecHandle = ASC->MakeOutgoingSpec(ClassDefaultInfo.PrimaryAttributes, Level, PrimaryContextHandle);
ASC->ApplyGameplayEffectSpecToSelf(*PrimarySpecHandle.Data.Get());
//设置次级属性
FGameplayEffectContextHandle SecondaryContextHandle = ASC->MakeEffectContext();
SecondaryContextHandle.AddSourceObject(AvatarActor);
const FGameplayEffectSpecHandle SecondarySpecHandle = ASC->MakeOutgoingSpec(ClassInfo->SecondaryAttributes, Level, SecondaryContextHandle);
ASC->ApplyGameplayEffectSpecToSelf(*SecondarySpecHandle.Data.Get());
//填充血量和蓝量
FGameplayEffectContextHandle VitalContextHandle = ASC->MakeEffectContext();
VitalContextHandle.AddSourceObject(AvatarActor);
const FGameplayEffectSpecHandle VitalSpecHandle = ASC->MakeOutgoingSpec(ClassInfo->VitalAttributes, Level, VitalContextHandle);
ASC->ApplyGameplayEffectSpecToSelf(*VitalSpecHandle.Data.Get());
}
然后需要在Enemy.h中设置 职业变量并 InitInfo使用上面实现的函数nitializeDefaultAttributes()
//TODO:: 用于给不同敌人划分不同职业
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Character Class Defaults" )
ECharacterClass CharacterClass = ECharacterClass::Warrior;
//重写父类初始化函数
virtual void InitializeDefaultAttributes() const override;
//--Enemt.cpp
void AAuraEnemy::InitAbilityActorInfo()
{
//初始化ActorInfo
AbilitySystemComponent->InitAbilityActorInfo(this,this);
//单向了解
Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent)->AbilityActorInfoSet();
//通过GE初始角色的属性
InitializeDefaultAttributes();
}
void AAuraEnemy::InitializeDefaultAttributes() const
{
//重写覆盖父类初始化函数,但删去Super
UMyASBlueprintFunctionLibrary::InitializeDefaultAttributes(this,CharacterClass,Level,AbilitySystemComponent);
}
调试验证
打断点处