13. UE5 RPG limita el rango de valores de atributos y genera estructuras

En los capítulos anteriores implementamos la modificación de los valores de los Atributos a través de GameplayEffect, como el volumen de sangre y el volumen de maná. Todos tenemos un volumen de sangre máximo y un volumen de maná máximo para limitar sus valores máximos y los valores mínimos. ​El volumen de salud y el volumen de maná no son iguales. será menor que cero. No implementamos restricciones relevantes antes, a continuación, debemos implementar restricciones de rango en los valores reales en la función AttributeSet.

lograr

Primero anule la función de la clase principal; en la función PreAttributeChange(), esta función activará una devolución de llamada antes de que cambie el valor monitoreado en AttributeSet.

virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;

La devolución de llamada devuelve dos parámetros. Uno es el atributo. Podemos usar este valor para determinar qué atributo se ha modificado. El otro es el valor que se va a modificar. A continuación, imprimimos el valor y vemos el resultado.

	if(Attribute == GetHealthAttribute())
	{
    
    
		UE_LOG(LogTemp, Warning, TEXT("Health: %f"), NewValue);
	}

	if(Attribute == GetMaxHealthAttribute())
	{
    
    
		UE_LOG(LogTemp, Warning, TEXT("MaxHealth: %f"), NewValue);
	}

	if(Attribute == GetManaAttribute())
	{
    
    
		UE_LOG(LogTemp, Warning, TEXT("Mana: %f"), NewValue);
	}

	if(Attribute == GetMaxManaAttribute())
	{
    
    
		UE_LOG(LogTemp, Warning, TEXT("MaxMana: %f"), NewValue);
	}

Compile y abra UE, haga clic en el registro de salida en la esquina inferior izquierda de la escena.
Insertar descripción de la imagen aquí
Seleccione para acoplarse en el diseño
Insertar descripción de la imagen aquí
y dejar que el personaje coma botellas de medicinas, cristales y pise fuegos para ver los cambios de atributos. Encontraremos que todos Los cambios de atributos se pueden reflejar verazmente en Imprima lo anterior
Insertar descripción de la imagen aquí
y luego use la función de sujeción para limitar los valores de salud y maná al rango de 0 a la salud y maná máximos.

NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());

Ejecute UE y verifique nuevamente y descubra que los valores están limitados dentro del rango.
Insertar descripción de la imagen aquí

PostGameplayEffectEjecutar

La función PostGameplayEffectExecute() se activa después de que cambia el valor. Generalmente, solo se puede activar mediante GameplayEffect de tipo Instantáneo (GameplayEffect de las clases Duration e Infinite también se puede activar si se establece Period).
Hay muchos escenarios de aplicación para esta función, podemos realizar algunas operaciones lógicas, como muerte, invencibilidad y sin deducción de sangre, etc.
Para usarlo, primero debemos anular la clase principal.

virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

Solo tiene un parámetro de retorno, Datos, pero Datos contiene mucho contenido.

	if(Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
    
    
		UE_LOG(LogTemp, Warning, TEXT("Health: %f"), GetHealth());
		UE_LOG(LogTemp, Warning, TEXT("Magnitude: %f"), Data.EvaluatedData.Magnitude);
	}

Abra UE para ver el volumen de sangre actual y el valor del daño causado por este efecto.
Insertar descripción de la imagen aquí
Cuando llegamos a un punto de interrupción, podemos
Insertar descripción de la imagen aquí
ver que hay tres datos en Data.
Insertar descripción de la imagen aquí
EffectSpec es la instancia del efecto que contiene una gran cantidad de datos. Podemos usarlo para obtener qué actor aplicó este GE al objetivo.
EvaluatedData es el contenido relacionado con los datos modificados. Valor actual, cuántos valores se han modificado, qué atributos se han modificado, etc. El
objetivo es el ASC del objetivo.
Insertar descripción de la imagen aquí
A continuación, obtendremos lo que necesitamos de los datos y lo encapsularemos en una estructura para su uso posterior.

Primero cree una estructura FEffectProperties para almacenar objetos relacionados con la conversión de GE y objetos relacionados con el objetivo. Esta estructura guarda el contexto GE y el carácter controlador ASC AvatarActor del lanzador y el objetivo.

USTRUCT()
struct FEffectProperties
{
    
    
	GENERATED_BODY()

	FEffectProperties(){
    
    }

	FGameplayEffectContextHandle EffectContextHandle;

	UPROPERTY()
	UAbilitySystemComponent* SourceASC = nullptr;

	UPROPERTY()
	AActor* SourceAvatarActor = nullptr;

	UPROPERTY()
	AController* SourceController = nullptr;

	UPROPERTY()
	ACharacter* SourceCharacter = nullptr;

	UPROPERTY()
	UAbilitySystemComponent* TargetASC = nullptr;

	UPROPERTY()
	AActor* TargetAvatarActor = nullptr;

	UPROPERTY()
	AController* TargetController = nullptr;

	UPROPERTY()
	ACharacter* TargetCharacter = nullptr;
};

A continuación, creamos una función privada en la que procesamos los valores de los atributos de la estructura generada. La función recibe dos valores, uno son los datos devueltos por la función PostGameplayEffectExecute() y el otro es la estructura que debe completarse.

static void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props);

A continuación, implemente la función y establezca las propiedades dentro de la función. Como se mencionó anteriormente, puede obtener las propiedades relevantes a través de Datos.

void UAttributeSetBase::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props)
{
    
    
	//Source 效果的所有者   Target 效果应用的目标

	Props.EffectContextHandle = Data.EffectSpec.GetContext();
	Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent(); //获取效果所有者的ASC

	//获取效果所有者的相关对象
	if(IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
	{
    
    
		Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get(); //获取Actor
		Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get(); //获取PlayerController
		if(Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
		{
    
    
			if(const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
			{
    
    
				Props.SourceController = Pawn->GetController();
			}
		}

		if(Props.SourceController)
		{
    
    
			Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
		}
	}

	if(Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
	{
    
    
		Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
		Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();
		Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);
		Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);
	}
}

Luego, solo necesitas crear una estructura dentro de PostGameplayEffectExecute() y llamar a la función para generar contenido.

void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    
    
	Super::PostGameplayEffectExecute(Data);

	FEffectProperties Props;
	SetEffectProperties(Data, Props);

}

Al usarlo, podemos obtener el contenido correspondiente a través de la estructura y la lógica es más clara.
Insertar descripción de la imagen aquí

código fuente

AtributoSetBase.h

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

#pragma once

#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "AttributeSetBase.generated.h"

// Uses macros from AttributeSet.h
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

USTRUCT()
struct FEffectProperties
{
    
    
	GENERATED_BODY()

	FEffectProperties(){
    
    }

	FGameplayEffectContextHandle EffectContextHandle;

	UPROPERTY()
	UAbilitySystemComponent* SourceASC = nullptr;

	UPROPERTY()
	AActor* SourceAvatarActor = nullptr;

	UPROPERTY()
	AController* SourceController = nullptr;

	UPROPERTY()
	ACharacter* SourceCharacter = nullptr;

	UPROPERTY()
	UAbilitySystemComponent* TargetASC = nullptr;

	UPROPERTY()
	AActor* TargetAvatarActor = nullptr;

	UPROPERTY()
	AController* TargetController = nullptr;

	UPROPERTY()
	ACharacter* TargetCharacter = nullptr;
};

/**
 * 技能系统属性集
 */
UCLASS()
class AURA_API UAttributeSetBase : public UAttributeSet
{
    
    
	GENERATED_BODY()

public:
	UAttributeSetBase();
	virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;

	virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
	virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

	UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_Health, Category="Vital Attributes")
	FGameplayAttributeData Health;
	ATTRIBUTE_ACCESSORS(UAttributeSetBase, Health);

	UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attributes")
	FGameplayAttributeData MaxHealth;
	ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxHealth);

	UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_Mana, Category="Vital Attributes")
	FGameplayAttributeData Mana;
	ATTRIBUTE_ACCESSORS(UAttributeSetBase, Mana);

	UPROPERTY(BlueprintReadOnly,ReplicatedUsing = OnRep_MaxMana, Category="Vital Attributes")
	FGameplayAttributeData MaxMana;
	ATTRIBUTE_ACCESSORS(UAttributeSetBase, MaxMana);

	UFUNCTION()
	void OnRep_Health(const FGameplayAttributeData& OldHealth) const;

	UFUNCTION()
	void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const;

	UFUNCTION()
	void OnRep_Mana(const FGameplayAttributeData& OldMana) const;

	UFUNCTION()
	void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const;

private:
	static void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props);
};

AtributoSetBase.cpp

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


#include "AbilitySystem/AttributeSetBase.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GameFramework/Character.h"
#include "Net/UnrealNetwork.h"

UAttributeSetBase::UAttributeSetBase()
{
    
    
	InitHealth(30.f);
	InitMaxHealth(100.f);
	InitMana(30.f);
	InitMaxMana(100.f);
}

void UAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
    
    
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Health, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, Mana, COND_None, REPNOTIFY_Always);
	DOREPLIFETIME_CONDITION_NOTIFY(UAttributeSetBase, MaxMana, COND_None, REPNOTIFY_Always);
}

void UAttributeSetBase::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
    
    
	Super::PreAttributeChange(Attribute, NewValue);

	if(Attribute == GetHealthAttribute())
	{
    
    
		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
		// UE_LOG(LogTemp, Warning, TEXT("Health: %f"), NewValue);
	}

	if(Attribute == GetManaAttribute())
	{
    
    
		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
	}
}

void UAttributeSetBase::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props)
{
    
    
	//Source 效果的所有者   Target 效果应用的目标

	Props.EffectContextHandle = Data.EffectSpec.GetContext();
	Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent(); //获取效果所有者的ASC

	//获取效果所有者的相关对象
	if(IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
	{
    
    
		Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get(); //获取Actor
		Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get(); //获取PlayerController
		if(Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
		{
    
    
			if(const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
			{
    
    
				Props.SourceController = Pawn->GetController();
			}
		}

		if(Props.SourceController)
		{
    
    
			Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
		}
	}

	if(Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
	{
    
    
		Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
		Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();
		Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);
		Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);
	}
}

void UAttributeSetBase::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
    
    
	Super::PostGameplayEffectExecute(Data);

	FEffectProperties Props;
	SetEffectProperties(Data, Props);
}

void UAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
    
    
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, Health, OldHealth);
}

void UAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{
    
    
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxHealth);
}

void UAttributeSetBase::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{
    
    
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMana);
}

void UAttributeSetBase::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{
    
    
	GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, MaxHealth, OldMaxMana);
}


Supongo que te gusta

Origin blog.csdn.net/qq_30100043/article/details/136058336
Recomendado
Clasificación