Replicated

[Drag Down] 이펙트로 어트리뷰트 사용 처리, 어트리뷰트 부족 시 어빌리티 사용 제한하기 본문

언리얼 엔진/Drag Down (캡스톤 디자인)

[Drag Down] 이펙트로 어트리뷰트 사용 처리, 어트리뷰트 부족 시 어빌리티 사용 제한하기

라구넹 2025. 4. 2. 14:02

1. 밀기, 점프 밀기, 회피 액션 시 스테미나 감소

2. 지속적인 체력 회복

 

둘 다 게임플레이 이펙트로 처리한다

SetByCallerMagnitude 사용해서 런타임에 조정하자

또 태그를 쓰자!

 

어트리뷰트를 대미지로 설정하진 않는다

대미지 입는게 아니라 직접 깎는 거라서..

대미지는 나중에 아이템 같은 거 맞으면 깎인다거나 할 때 이용할 것이다

 

 

void UDDGA_PushingCharacter::ActivateAbility(const FGameplayAbilitySpecHandle Handle,
	const FGameplayAbilityActorInfo* ActorInfo, 
	const FGameplayAbilityActivationInfo ActivationInfo, 
	const FGameplayEventData* TriggerEventData)
{
	Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
	
	...

	if (UAbilitySystemComponent* ASC = ActorInfo->AbilitySystemComponent.Get())
	{
		ASC->AddLooseGameplayTag(FGameplayTag::RequestGameplayTag(FName("Player.State.UsingAbility")));

		FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(DownStaminaEffect);
		if (EffectSpecHandle.IsValid())
		{
			EffectSpecHandle.Data->SetSetByCallerMagnitude( FGameplayTag::RequestGameplayTag(FName("Data.StaminaUsed")), -AttackStateComponent->GetNecessaryStamina());
			ApplyGameplayEffectSpecToOwner(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle);
		}
	}
	...

어빌리티 발동 시 이펙트를 SetByCaller로 적용한다

 

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "DDStateDrivenAttackData.generated.h"

/**
 * 
 */
UCLASS()
class DRAGDOWN_API UDDStateDrivenAttackData : public UDataAsset
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditAnywhere, Category = "Name")
	FString MontageSectionNamePrefix;

	UPROPERTY(EditAnywhere, Category = "Name")
	uint8 MaxStateCount;

	UPROPERTY(EditAnywhere, Category = "ComboData")
	TArray< float > AttackPower;

	UPROPERTY(EditAnywhere, Category = "ComboData")
	TArray< float > ZPower;

	UPROPERTY(EditAnywhere, Category = "ComboData")
	TArray< float > NecessaryStamina;
};


// Fill out your copyright notice in the Description page of Project Settings.


#include "ActorComponent/DDAttackStateComponent.h"
#include "DataAsset/DDStateDrivenAttackData.h"

// Sets default values for this component's properties
UDDAttackStateComponent::UDDAttackStateComponent()
{
	NowAttackState = 0;

	static ConstructorHelpers::FObjectFinder<UDDStateDrivenAttackData> DataAssetRef(TEXT("/Script/DragDown.DDStateDrivenAttackData'/Game/Blueprint/DataAsset/DDDA_DirevenAttackData.DDDA_DirevenAttackData'"));

	if ( DataAssetRef.Succeeded() )
	{
		StateDrivenAttackData = DataAssetRef.Object;
		MaxAttackState = DataAssetRef.Object.Get()->MaxStateCount;
	}
}

FString UDDAttackStateComponent::GetSectionPrefix()
{
	if (StateDrivenAttackData) return StateDrivenAttackData->MontageSectionNamePrefix;
	return FString();
}

float UDDAttackStateComponent::GetPower()
{
	if (StateDrivenAttackData) return StateDrivenAttackData->AttackPower[NowAttackState];
	return 0.0f;
}

float UDDAttackStateComponent::GetZPower()
{
	if (StateDrivenAttackData) return StateDrivenAttackData->ZPower[NowAttackState];
	return 0.0f;
}

float UDDAttackStateComponent::GetNecessaryStamina()
{
	if (StateDrivenAttackData) return StateDrivenAttackData->NecessaryStamina[NowAttackState];
	return 0.0f;
}

상태기반 공격의 경우, 데이터 애셋에서 값을 조절하고 관리 컴포넌트에서 값을 관리한다

점프 공격이나 회피는 그냥 내부 변수에 담아두고 쓴다

 

상태기반 공격은 0, 1번 공격은 20 / 2, 3번 공격은 30만큼 스태미나가 깎이도록 설정

 

스태미나가 잘 적용된다

 

 

근데 이제 스태미나가 없으면 발동이 안되게 해야 한다

CanActivateAbility를 써 보자

 

bool UDDGA_PushingCharacter::CanActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayTagContainer* SourceTags, const FGameplayTagContainer* TargetTags, OUT FGameplayTagContainer* OptionalRelevantTags) const
{
	if (!Super::CanActivateAbility(Handle, ActorInfo, SourceTags, TargetTags, OptionalRelevantTags))
	{
		return false;
	}

	UAbilitySystemComponent* ASC = ActorInfo->AbilitySystemComponent.Get();
	if (ASC == nullptr) return false;

	const UDDAttributeSet* AttributeSet = ASC->GetSet<UDDAttributeSet>();
	if (AttributeSet == nullptr) return false;

	float CurrentStamina = AttributeSet->GetStamina();

	if (CurrentStamina < AttackStateComponent->GetNecessaryStamina())
	{
		return false;
	}

	return true;
}

어트리뷰트 들고 와서 체크하면 된다!

그런데 CanActivateAbility가 AcativateAbility보다 먼저 발동되기 때문에, 관련 초기화를 미리 해놔야 한다

 

void UDDGA_PushingCharacter::OnGiveAbility(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
{
	삭제
}

OnGiveAbility에서 처리해주면 된다

절대 안된다. 클라이언트에서 작동 안한다.

GiveAbility는 애초에 서버만 가능해서 불가능하다.

 

void UDDGA_JumpPushingCharacter::OnAvatarSet(const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilitySpec& Spec)
{
	Super::OnAvatarSet(ActorInfo, Spec);

	AvatarCharacter = Cast<ACharacter>(ActorInfo->AvatarActor.Get());
}

대신 OnAvatarSet에서 가능하다

 

그런데 이제 슬슬 코드를 리팩토링 좀 해야 할 것 같다

어빌리티 상위 클래스 만들어서 겹치는 코드 좀 옮기고, 게임플레이 태그 매니저를 만들어야 할 것 같다

 

일단 스테미나 자동회복이랑 스테미나 UI 만들고 연결만 한 다음에 해야겠다