일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- Multiplay
- os
- gas
- local prediction
- 언리얼엔진
- UI
- gameplay tag
- 메카님
- rpc
- ret2libc
- gameplay ability system
- Unreal Engine
- Aegis
- dirty cow
- 게임개발
- animation
- ability task
- map design
- gravity direction
- MAC
- attribute
- 유니티
- listen server
- 언리얼 엔진
- Replication
- gameplay effect
- 게임 개발
- photon fusion2
- CTF
- unity
- Today
- Total
Replicated
[Drag Down] 이펙트로 어트리뷰트 사용 처리, 어트리뷰트 부족 시 어빌리티 사용 제한하기 본문
[Drag Down] 이펙트로 어트리뷰트 사용 처리, 어트리뷰트 부족 시 어빌리티 사용 제한하기
라구넹 2025. 4. 2. 14:021. 밀기, 점프 밀기, 회피 액션 시 스테미나 감소
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 만들고 연결만 한 다음에 해야겠다
'언리얼 엔진 > Drag Down (캡스톤 디자인)' 카테고리의 다른 글
** [Drag Down] Local Prediction시 외부 컴포넌트의 동기화 ** (0) | 2025.04.03 |
---|---|
[Drag Down] 멀티 환경에서 스테미나 UI 제작 및 GAS 연결 (0) | 2025.04.02 |
[Drag Down] Gameplay Tag로 어빌리티 꼬임 방지 (0) | 2025.04.02 |
[Drag Down] 회피 만들기 (0) | 2025.04.01 |
** [Drag Down] RPC In Local Prediction (feat. Root Motion) / (서버->클라이언트 애니메이션 동기화 문제) ** (0) | 2025.03.31 |