22. UE5 RPG使用MMC根据等级设置血量和蓝量(下)

44 篇文章 6 订阅

上一篇,我们实现了玩家角色和敌人的等级的获取,使用MMC的提前工作已经准备完成,那么,这一篇讲一下,如何使用MMC,通过角色等级和体力值设置角色的最大血量。
MMC 全称 Mod Magnitude Calculation,为自定义计算数值的类,可以使用蓝图继承,也可以使用c++继承,在这个项目里面我们使用的c++实现。
它需要我们覆写父类的函数CalculateBaseMagnitude_Implementation(),在内部实现计算并返回,接下来,我们将先实现对等级属性和在AS里的体力属性的获取,然后计算并返回。

创建MMC

打开UE,创建C++类,选择所有类,在里面找到GameplayModeMagnitudeCalculation类作为基类
在这里插入图片描述
创建类,放到一个单独的文件夹,后续我们可能需要制作很多的MMC
在这里插入图片描述
添加完成后,就可以将UE关闭,在编辑器内编写MMC代码了。

打开首先添加一个构造函数,我们需要在构造函数内去设置需要获取的AS属性

public:
	UMMC_MaxHealth();

我们需要覆盖父类的CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec),这个函数返回了一个应用此MMC的GE的实例,我们可以通过Spec去获取需要的内容,然后计算数值。

virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;

创建一个FGameplayEffectAttributeCaptureDefinition 属性,我们会在cpp文件内,使用它去获取AS内的体力的值。

private:

	FGameplayEffectAttributeCaptureDefinition VigorDef;

以下为.h文件的代码

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

#pragma once

#include "CoreMinimal.h"
#include "GameplayModMagnitudeCalculation.h"
#include "MMC_MaxHealth.generated.h"

/**
 * 
 */
UCLASS()
class AURA_API UMMC_MaxHealth : public UGameplayModMagnitudeCalculation
{
	GENERATED_BODY()

public:
	UMMC_MaxHealth();

	virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;

private:

	FGameplayEffectAttributeCaptureDefinition VigorDef;
};

接着转到cpp文件内,编写构造函数,设置需要拾取的参数的内容,用于拾取目标身上的属性的值。

UMMC_MaxHealth::UMMC_MaxHealth()
{
	VigorDef.AttributeToCapture = UAttributeSetBase::GetVigorAttribute(); //设置需要获取的属性对象
	VigorDef.AttributeSource = EGameplayEffectAttributeCaptureSource::Target; //设置拾取对象为GE的应用目标
	VigorDef.bSnapshot = false;

	RelevantAttributesToCapture.Add(VigorDef); //添加到捕获属性数值,只有添加到列表,才会去获取属性值
}

接下来,就是编写CalculateBaseMagnitude_Implementation()函数,我们首先要实现对体力值的获取。获取使用到的函数是GetCapturedAttributeMagnitude(),里面需要FAggregatorEvaluateParameters 参数,那么我们先创建此参数,并设置目标和源的Tag设置给它

	//  从 source 和 target 获取 Tag
	const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
	const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

	FAggregatorEvaluateParameters EvaluateParameters;
	EvaluateParameters.SourceTags = SourceTags;
	EvaluateParameters.TargetTags = TargetTags;

	float Vigor = 0.f;
	GetCapturedAttributeMagnitude(VigorDef, Spec, EvaluateParameters, Vigor);
	Vigor = FMath::Max<float>(Vigor, 0.f);

体力获取到了,我们还需要获取它的等级,获取等级需要此GE的应用源,可以通过Spec.GetContext().GetSourceObject()去获取源对象,当然,你不设置是获取不到的,这个需要在应用GE的时候,设置源,设置方法如下

void ACharacterBase::ApplyEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level) const
{
	check(IsValid(GetAbilitySystemComponent()));
	check(GameplayEffectClass);
	
	FGameplayEffectContextHandle ContextHandle = GetAbilitySystemComponent()->MakeEffectContext();
	ContextHandle.AddSourceObject(this); //设置源对象,可以通过Spec.GetContext().GetSourceObject()去获取源对象
	const FGameplayEffectSpecHandle SpecHandle = GetAbilitySystemComponent()->MakeOutgoingSpec(GameplayEffectClass, Level, ContextHandle);
	GetAbilitySystemComponent()->ApplyGameplayEffectSpecToTarget(*SpecHandle.Data.Get(), GetAbilitySystemComponent());
}

能获取到应用GE的对象,那么,也就是玩家角色自身,我们就可以从玩家角色身上调用GetPlayerLevel()函数获取等级

	//获取等级
	ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
	const int32 Level = CombatInterface->GetPlayerLevel();

体力和等级我们都已经拿到,那么,应用我们自身的公式,得出最大血量结果

	//计算最大血量
	return 80.f + Vigor * 2.5f + Level * 10.f;

以下为cpp的完整代码

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


#include "AbilitySystem/ModMagCalc/MMC_MaxHealth.h"

#include "AbilitySystem/AttributeSetBase.h"
#include "Interaction/CombatInterface.h"

UMMC_MaxHealth::UMMC_MaxHealth()
{
	VigorDef.AttributeToCapture = UAttributeSetBase::GetVigorAttribute(); //设置需要获取的属性对象
	VigorDef.AttributeSource = EGameplayEffectAttributeCaptureSource::Target; //设置拾取对象为GE的应用目标
	VigorDef.bSnapshot = false;

	RelevantAttributesToCapture.Add(VigorDef); //添加到捕获属性数值,只有添加到列表,才会去获取属性值
}

float UMMC_MaxHealth::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
{
	//  从 source 和 target 获取 Tag
	const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
	const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

	FAggregatorEvaluateParameters EvaluateParameters;
	EvaluateParameters.SourceTags = SourceTags;
	EvaluateParameters.TargetTags = TargetTags;

	//获取体力值
	float Vigor = 0.f;
	GetCapturedAttributeMagnitude(VigorDef, Spec, EvaluateParameters, Vigor);
	Vigor = FMath::Max<float>(Vigor, 0.f);

	//获取等级
	ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
	const int32 Level = CombatInterface->GetPlayerLevel();

	//计算最大血量
	return 80.f + Vigor * 2.5f + Level * 10.f;
}

编写完成以后,就可以进行编译,进入UE中设置,type修改为Custom Calculation Class,Class设置上我们刚才制作的MMC
在这里插入图片描述
完成以后运行,查看效果,我们等级现在设置的是1, Vigor是23 那么结果就应该是 80 + 23*2.5 + 1 * 10 = 147.5,数值可以对起来
在这里插入图片描述
打个断点,看一下值,没有问题
在这里插入图片描述
这里,我们就实现了对最大血量的设置。
接下来,按照同样的道理,我们再创建一个MMC_MaxMana用于处理最大蓝量,这里我就不再赘述了,和最大血量一个道理,直接贴代码。

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

#pragma once

#include "CoreMinimal.h"
#include "GameplayModMagnitudeCalculation.h"
#include "MMC_MaxMana.generated.h"

/**
 * 
 */
UCLASS()
class AURA_API UMMC_MaxMana : public UGameplayModMagnitudeCalculation
{
	GENERATED_BODY()

public:
	UMMC_MaxMana();

	virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;

private:

	FGameplayEffectAttributeCaptureDefinition IntelligenceDef;
	
};

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


#include "AbilitySystem/ModMagCalc/MMC_MaxMana.h"

#include "AbilitySystem/AttributeSetBase.h"
#include "Interaction/CombatInterface.h"

UMMC_MaxMana::UMMC_MaxMana()
{
	IntelligenceDef.AttributeToCapture = UAttributeSetBase::GetIntelligenceAttribute(); //设置需要获取的属性对象
	IntelligenceDef.AttributeSource = EGameplayEffectAttributeCaptureSource::Target; //设置拾取对象为GE的应用目标
	IntelligenceDef.bSnapshot = false;

	RelevantAttributesToCapture.Add(IntelligenceDef); //添加到捕获属性数值,只有添加到列表,才会去获取属性值
}

float UMMC_MaxMana::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
{
	//  从 source 和 target 获取 Tag
	const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
	const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

	FAggregatorEvaluateParameters EvaluateParameters;
	EvaluateParameters.SourceTags = SourceTags;
	EvaluateParameters.TargetTags = TargetTags;

	//获取体力值
	float Intelligence = 0.f;
	GetCapturedAttributeMagnitude(IntelligenceDef, Spec, EvaluateParameters, Intelligence);
	Intelligence = FMath::Max<float>(Intelligence, 0.f);

	//获取等级
	ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
	const int32 Level = CombatInterface->GetPlayerLevel();

	//计算最大血量
	return 50.f + Intelligence * 2.5f + Level * 15.f;
}

智力为21 等级为1 50 + 21 * 2.5f + 15 = 117.5 数值正确。
在这里插入图片描述
上面就是MMC的创建。

初始化血量和蓝量

在设置完最大血量和最大蓝量后,我们会发现血量和蓝量的都是不满的,接下来,我们要将药瓶填满。
在这里插入图片描述
在角色基类上面,我们已经完成对PrimaryAttribute和SecondaryAttribute的初始化
在这里插入图片描述
我们在下面接着增加一个参数配置,可以配置更多一个GE

	UPROPERTY(BlueprintReadOnly, EditAnywhere, Category="Attributes")
	TSubclassOf<UGameplayEffect> DefaultVitalAttributes;

在应用GE时,也应用到自身,注意顺序,不能乱

void ACharacterBase::InitializeDefaultAttributes() const
{
	ApplyEffectToSelf(DefaultPrimaryAttributes, 1.f);
	ApplyEffectToSelf(DefaultSecondaryAttributes, 1.f);
	ApplyEffectToSelf(DefaultVitalAttributes, 1.f);
}

接着创建第三个初始化GE,我们这次使用Instant,在设置完成最大血量和最大蓝量,血量和蓝量填满即可
在这里插入图片描述
这里只需要使用Attribute Based 基于最大血量和蓝量一比一填入即可
在这里插入图片描述
将GE设置到角色身上
在这里插入图片描述
药瓶满了
在这里插入图片描述
可以看到最大血量和血量,最大蓝量和蓝量数值相同了
在这里插入图片描述

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值