일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- 게임 개발
- stride
- pdlc
- reverse gravity
- CTF
- 유니티
- DSP
- dirty cow
- Security
- DP
- Race condition
- MAC
- ability task
- 메카님
- gas
- sampling theory
- linear difference equation
- Rr
- 운영체제
- MLFQ
- 게임개발
- dtft
- gameplay effect
- gameplay ability
- 언리얼 엔진
- frequency-domain spectrum analysis
- 언리얼엔진
- ret2libc
- 유스케이스
- Unreal Engine
- Today
- Total
다양한 기록
[Unreal GAS] Gameplay Effect 본문
게임플레이 이펙트
- GE
- GAS는 게임에 영향을 주는 객체를 별도로 분리해서 관리함 (특수효과 아님)
- 게임에 영향 => 게임 데이터를 변경한다는 뜻
- => 게임플레이 이펙트와 어트리뷰트는 함께 동작하도록 구성됨
- GAS에서 가장 많은 기능을 제공
- 세가지 타입
- Instant : 어트리뷰트에 즉각적으로 적용되는 게임플레이 이펙트, 한 프레임에 실행
- Duration : 지정한 시간 동안 동작
- Infinite : 명시적으로 종료하지 않으면 계속 동작
gameplayeffect 클래스 생성
게임플레이 이펙트 모디파이어(Modifier)
- GE에서 어트리뷰트의 변경 방법을 지정한 설정
- 모티파이어의 사용 방법
- 적용할 어트리뷰트의 지정
- 적용 방식의 설정 : 더하기, 곱하기, 나누기, 덮어쓰기
- 모디파이어의 계산 방법
- ScalableFloat : 실수(데이터테이블과 연동 가능)
- AttributeBased : 특정 어트리뷰트 기반
- CustomCalculationClass : 계산을 담당하는 전용 클래스의 활용
- SetByCaller : 데이터 태그를 활용한 데이터 전달 (대미지를 전달하는 주체가 데이터 다 준비하고 받기만 하라고 날림)
- 모디파이어 없이 자체 계산 로직을 만드는 것도 가능 (GameplayEffectExecutionCalculation)
문법이 복잡해서 블루프린트로 제작하는 것이 권장됨
Attribute에 접근할 수 있도록 이펙트 프렌드 클래스로 적용
// Fill out your copyright notice in the Description page of Project Settings.
#include "GA/GE/ABGE_AttackDamage.h"
#include "Attribute/ABCharacterAttributeSet.h"
UABGE_AttackDamage::UABGE_AttackDamage()
{
DurationPolicy = EGameplayEffectDurationType::Instant;
FGameplayModifierInfo HealthModifier;
HealthModifier.Attribute = FGameplayAttribute(FindFieldChecked<FProperty>(UABCharacterAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(UABCharacterAttributeSet, Health)));
HealthModifier.ModifierOp = EGameplayModOp::Additive;
FScalableFloat DamageAmount(-30.0f);
FGameplayEffectModifierMagnitude ModMagnitude(DamageAmount);
HealthModifier.ModifierMagnitude = ModMagnitude;
Modifiers.Add(HealthModifier);
}
이펙트에선 모티파이어 만들고 / 오퍼레이션 정하고 / 적용시킬 값 설정해줘야 함
void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if ( UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0) )
{
FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0);
ABGAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *HitResult.GetActor()->GetName());
/*UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked();
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(HitResult.GetActor());
if ( !SourceASC || !TargetASC )
{
ABGAS_LOG(LogABGAS, Error, TEXT("ASC Not Found.."));
return;
}
const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>();
UABCharacterAttributeSet* TargetAttribute = const_cast<UABCharacterAttributeSet*>(TargetASC->GetSet<UABCharacterAttributeSet>());
if ( !SourceAttribute || !TargetAttribute )
{
ABGAS_LOG(LogABGAS, Error, TEXT("Attribute Not Found.."));
return;
}
const float AttackDamage = SourceAttribute->GetAttackRate();
TargetAttribute->SetHealth(TargetAttribute->GetHealth() - AttackDamage);*/
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackDamageEffect);
if (EffectSpecHandle.IsValid())
{
ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
}
}
어빌리티에선 이제 잡다한 코드 다 날리고 Effect에 대한 스펙 핸들만 만들어서 넘기면 됨
적용해주고 플레이하면 정상 실행 확인 가능
근데 솔직히 번거로워서 보통 이걸 C++로 작업하진 않음
블루프린트 만들기
들어가서 설정 조금 만지면 결과 똑같음
게임플레이에서 설정 바꾸고 적용하면 됨
다음은 SetByCaller 이용
태그가 필요한데, 태그를 전송하는 사람이 지정한 값을 그냥 적용시킴
태그 추가
태그 설정
void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if ( UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0) )
{
FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0);
ABGAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *HitResult.GetActor()->GetName());
UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked();
const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>();
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackDamageEffect);
if (EffectSpecHandle.IsValid())
{
EffectSpecHandle.Data->SetSetByCallerMagnitude(ABTAG_DATA_DAMAGE, -SourceAttribute->GetAttackRate());
ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
}
}
bool bReplicatedEndAbility = true;
bool bWasCancelled = false;
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, bReplicatedEndAbility, bWasCancelled);
}
SetSetByCaller~에서 값을 설정하면 됨
다음은 Custom Calculation Class
ModMagnitudeCalculation 만들기
Function 만들고
값 지정 (Spec에서 다양한 설정 가능)
GE에서 클래스 지정
다음은 Attribute Based
누구의 어떤 Attribute를 들고 와서 어떤 값을 곱하고, 그 전후에 또 어떤 값을 더해줄 건지도 설정 가능
메타(Meta) 어트리뷰트
- 어트리뷰트의 설정을 위해 사전에 미리 설정하는 임시 어트리뷰트
- ex. 체력을 바로 깎지 않고 대미지를 통해 체력을 감소하도록 설정
- 체력은 일반 어트리뷰트, 대미지는 메타 어트리뷰트
- 대미지를 사용하는 경우 기획 추가에 유연한 대처가 가능
- 무적 기능의 추가 (대미지를 0으로 처리)
- 실드 기능의 추가 (실드 값을 토대로 실드 값만큼 대미지 처리)
- 콤보 진행 시 공격력 보정 기능 추가 (콤보 증가 시 대미지를 보정하도록 구현)
- 메타 어트리뷰트는 적용 후 바로 0으로 값을 초기화하도록 설정
- 메타 어트리뷰트는 리플리케이션에서 제외시키는 것이 일반적
일반 어트리뷰트처럼 만들고
생성자에서 설정해주고
void UABCharacterAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
/*if ( Attribute == GetHealthAttribute() )
{
NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxHealth());
}*/
if ( Attribute == GetDamageAttribute() )
{
NewValue = (NewValue < 0.0f) ? 0.0f : NewValue;
}
}
void UABCharacterAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if ( Data.EvaluatedData.Attribute == GetDamageAttribute() )
{
SetHealth(FMath::Clamp(GetHealth() - GetDamage(), 0.0f, GetMaxHealth()));
SetDamage(0.0f);
}
}
PostGameplayEffectExecute에서 대미지 변경 시 체력을 설정하도록 로직 변경
이펙트 설정도 변경
이제 콤보 공격 시 대미지 증가를 구현해야 함
레벨과 커브 테이블
- 게임플레이 이펙트에는 추가적으로 레벨 정보를 지정할 수 있음
- 게임플레이 이펙트에는 저장된 레벨 정보를 사용해 데이터 테이블에서 특정 값을 가져올 수 있음
- ScalableFloat 모디파이어 타입에서 사용 가능
- 콤보 추가 시 대미지 증가, 캐릭터 레벨에 따른 초기 스탯 적용 등이 가능
선형적으로 증가하도록 커브테이블 생성
커브에 행 만들기
애니메이션 노티파이에서 프로퍼티 만들고
생성자 설정 및
void UAnimNotify_GASAttackHitCheck::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, const FAnimNotifyEventReference& EventReference)
{
Super::Notify(MeshComp, Animation, EventReference);
if ( MeshComp )
{
AActor* OwnerActor = MeshComp->GetOwner();
if ( OwnerActor )
{
FGameplayEventData PayloadData;
PayloadData.EventMagnitude = ComboAttackLevel;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(OwnerActor, TriggerGameplayTag, PayloadData);
}
}
}
페이로드에 데이터 추가
보내면 이제 콤보 레벨이 같이 보내짐
void UABGA_AttackHitCheck::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
CurrentLevel = TriggerEventData->EventMagnitude;
ABGAS_LOG(LogABGAS, Log, TEXT("Begin"));
UABAT_Trace* AttackTraceTask = UABAT_Trace::CreateTask(this, AABTA_Trace::StaticClass());
AttackTraceTask->OnComplete.AddDynamic(this, &UABGA_AttackHitCheck::OnTraceResultCallback);
AttackTraceTask->ReadyForActivation();
}
그리고 GA에서 액티베이트 될 때 트리거 이벤트 데이터에서 꺼내오면 됨
스펙 만들 때 두번째 인자로 레벨 전달
나머지는 블루프린트에서 해야 함
애니메이션에서 레벨 설정
Coefficient에서 커브테이블 설정 해주면 됨
다음은 캐릭터에 레벨 부여
레벨이 오르면 체력이 오름
게임 이펙트인 경우엔 캐릭터 초기 스탯 지정에도 사용 가능
어빌리티를 발동시키지 않아도 어빌리티 시스템 컴포넌트에서 이펙트 발동을 할 수 있음
설정
NPC 블루프린트 만들고
기본 설정
게임플레이 이펙트의 생성 과정
- 게임플레이 이펙트 컨텍스트와 게임플레이 이펙트 스펙을 통해 생성 가능
- 게임플레이 이펙트 컨텍스트 : GE에서 계산에 필요한 데이터를 담은 객체
- 가해자(Instigator), 가해수단(Causor), 판정정보(HitResult) 등등
- 게임플레이 이펙트 스펙 : GE와 관련된 정보를 담고 있는 객체
- 레벨, 모디파이어 및 각종 태그에 대한 정보
- 게임플레이 이펙트 컨텍스트 핸들
- ASC는 각 데이터를 핸들 객체를 통해 간접적으로 관리함
- 이펙트 컨텍스트 핸들을 만든 후, 이펙트 스펙 핸들 핸들을 생성하는 순서로 진행되어야 함
void AABGASCharacterNonPlayer::PossessedBy(AController* NewController)
{
Super::PossessedBy(NewController);
ASC->InitAbilityActorInfo(this, this);
FGameplayEffectContextHandle EffectContextHandle = ASC->MakeEffectContext();
EffectContextHandle.AddSourceObject(this);
FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(InitStatEffect, Level, EffectContextHandle);
if (EffectSpecHandle.IsValid())
{
ASC->BP_ApplyGameplayEffectSpecToSelf(EffectSpecHandle);
}
}
NPC cpp의 PossessedBy에서
컨텍스트 핸들 만들고 스펙 핸들에 집어넣기
ASC에서 GA 없이 활성화
그다음 NPC에서 세팅
NPC의 체력 세팅 확인 가능
'언리얼 엔진 > Unreal Ability System' 카테고리의 다른 글
[Unreal GAS] Integration with Attribute & UI (0) | 2025.01.19 |
---|---|
[Unreal GAS] Character Attribute Setting (0) | 2025.01.13 |
[Unreal GAS] Implementing Attack Hit Detect System (0) | 2025.01.13 |
[Unreal GAS] Implementing Combo Action (0) | 2025.01.12 |
[Unreal GAS] Character Input Handling (0) | 2025.01.12 |