PART 5 - 강의 1/2
GameplayCue 타입별 활용
시각/청각 피드백 시스템
01
GameplayCue 개요
시각/청각 피드백 분리
GameplayCue는 게임플레이 로직과 시각/청각 피드백을 분리하는 시스템입니다. 이를 통해 서버에서는 로직만, 클라이언트에서는 이펙트만 처리하여 네트워크 효율성을 높입니다.
GameplayCue의 장점
- 분리된 책임 - 게임플레이 로직과 피드백 분리
- 네트워크 효율 - 서버는 로직, 클라이언트는 이펙트
- 재사용성 - 여러 어빌리티에서 같은 Cue 사용 가능
- 에디터 통합 - 블루프린트에서 쉽게 구성
02
Static vs Actor Cue
두 가지 Cue 타입
GameplayCue 타입 비교
// 1. GameplayCueNotify_Static (기본 클래스)
// - 인스턴스 없이 CDO에서 직접 실행
// - 가볍고 빠름, 상태 저장 불가
// - 파티클, 사운드 한 번 재생에 적합
UCLASS()
class UGC_BurstEffect : public UGameplayCueNotify_Static
{
GENERATED_BODY()
public:
virtual bool OnExecute_Implementation(
AActor* Target,
const FGameplayCueParameters& Parameters) const override
{
// 파티클 스폰
if (BurstParticle)
{
UNiagaraFunctionLibrary::SpawnSystemAtLocation(
Target->GetWorld(),
BurstParticle,
Parameters.Location);
}
// 사운드 재생
if (BurstSound)
{
UGameplayStatics::PlaySoundAtLocation(
Target, BurstSound, Parameters.Location);
}
return true;
}
protected:
UPROPERTY(EditDefaultsOnly)
UNiagaraSystem* BurstParticle;
UPROPERTY(EditDefaultsOnly)
USoundBase* BurstSound;
};
Actor 기반 Cue
// 2. AGameplayCueNotify_Actor
// - 월드에 Actor로 스폰
// - 상태 저장 가능, 지속 효과에 적합
// - 버프 아이콘, 지속 파티클 등
UCLASS()
class AGC_BurningEffect : public AGameplayCueNotify_Actor
{
GENERATED_BODY()
public:
// 지속 효과 시작
virtual bool OnActive_Implementation(
AActor* Target,
const FGameplayCueParameters& Parameters) override
{
AttachToActor(Target, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
if (FireParticleComponent)
{
FireParticleComponent->Activate();
}
return true;
}
// 지속 효과 종료
virtual bool OnRemove_Implementation(
AActor* Target,
const FGameplayCueParameters& Parameters) override
{
if (FireParticleComponent)
{
FireParticleComponent->Deactivate();
}
// Actor 제거 예약
SetLifeSpan(2.0f);
return true;
}
protected:
UPROPERTY(VisibleAnywhere)
UNiagaraComponent* FireParticleComponent;
};
| 타입 | 인스턴스 | 상태 | 용도 |
|---|---|---|---|
| Static | CDO 사용 | 불가 | 일회성 효과 |
| Actor | Actor 스폰 | 가능 | 지속 효과 |
03
Cue 이벤트 타입
OnExecute, OnActive, OnRemove, WhileActive
Cue 이벤트 종류
// GameplayCue 이벤트 타입
enum class EGameplayCueEvent : uint8
{
// 즉시 실행 (Instant GameplayEffect)
OnExecute,
// 지속 효과 시작 (Duration/Infinite Effect)
OnActive,
// 지속 효과 종료
OnRemove,
// 매 틱마다 (Actor Cue만)
WhileActive
};
// Actor Cue에서 WhileActive 활용
virtual bool WhileActive_Implementation(
AActor* Target,
const FGameplayCueParameters& Parameters) override
{
// 스택 카운트에 따른 이펙트 강도 조절
float Intensity = Parameters.RawMagnitude;
if (FireParticleComponent)
{
FireParticleComponent->SetFloatParameter(
FName("Intensity"), Intensity);
}
return true;
}
Cue 이벤트 선택
OnExecute는 Instant Effect에, OnActive/OnRemove는 Duration/Infinite Effect에 사용됩니다. WhileActive는 Actor Cue에서만 매 틱 호출됩니다.
04
Cue 호출 방법
Effect와 수동 호출
GameplayCue 호출 방법
// 방법 1: GameplayEffect에서 자동 호출
// Blueprint에서 GameplayEffect의 GameplayCue Tags 배열에 태그 추가
// GameplayCue.Damage.Fire 등
// 방법 2: C++에서 수동 호출
void UGA_FireBall::ActivateAbility(...)
{
// 즉시 실행 Cue
FGameplayCueParameters CueParams;
CueParams.Location = GetAvatarActorFromActorInfo()->GetActorLocation();
CueParams.Normal = GetAvatarActorFromActorInfo()->GetActorForwardVector();
CueParams.RawMagnitude = 1.0f;
// Execute (일회성)
K2_ExecuteGameplayCue(
FGameplayTag::RequestGameplayTag(FName("GameplayCue.Ability.FireBall.Launch")),
CueParams);
}
// 지속 Cue 추가/제거
void UGA_BurningDebuff::ApplyBurning()
{
FGameplayCueParameters CueParams;
CueParams.RawMagnitude = StackCount;
// Add (지속 효과 시작)
K2_AddGameplayCue(
FGameplayTag::RequestGameplayTag(FName("GameplayCue.Status.Burning")),
CueParams);
}
void UGA_BurningDebuff::RemoveBurning()
{
// Remove (지속 효과 종료)
K2_RemoveGameplayCue(
FGameplayTag::RequestGameplayTag(FName("GameplayCue.Status.Burning")));
}
05
Cue Parameters
Cue에 데이터 전달
FGameplayCueParameters 구조체
struct FGameplayCueParameters
{
// 월드 위치
FVector Location;
// 노말 방향
FVector Normal;
// Effect Context (소스/타겟 정보)
FGameplayEffectContextHandle EffectContext;
// 소스 오브젝트
TWeakObjectPtr<UObject> SourceObject;
// 물리 머터리얼
TWeakObjectPtr<UPhysicalMaterial> PhysicalMaterial;
// 원본 수치 (스택 카운트 등)
float RawMagnitude;
// 정규화된 수치 (0~1)
float NormalizedMagnitude;
// GameplayEffect Level
float AbilityLevel;
};
// 커스텀 데이터 전달
void PassCustomDataToCue()
{
FGameplayCueParameters CueParams;
// EffectContext를 통한 커스텀 데이터 전달
FGameplayEffectContextHandle ContextHandle =
AbilitySystemComponent->MakeEffectContext();
// 커스텀 Context 사용 시
FMyGameplayEffectContext* MyContext =
static_cast<FMyGameplayEffectContext*>(ContextHandle.Get());
MyContext->SetCustomData(MyData);
CueParams.EffectContext = ContextHandle;
CueParams.RawMagnitude = DamageAmount;
K2_ExecuteGameplayCue(CueTag, CueParams);
}
SUMMARY
핵심 요약
- Static Cue: CDO 사용, 일회성 효과 (파티클, 사운드)
- Actor Cue: Actor 스폰, 지속 효과 (버프 이펙트)
- OnExecute: Instant Effect, OnActive/OnRemove: Duration Effect
- K2_ExecuteGameplayCue: 일회성, K2_AddGameplayCue: 지속 시작
- FGameplayCueParameters로 위치, 강도 등 데이터 전달
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: Static vs Actor Cue
GameplayCue.Hit (Static, 일회성)과 GameplayCue.Buff.Fire (Actor, 지속) 각각을 구현하세요. UGameplayCueNotify_Static에서 파티클 스폰, AGameplayCueNotify_Actor에서 루프 이펙트를 재생하세요.
실습 2: Cue Parameters 활용
FGameplayCueParameters의 Location, Normal, EffectContext를 사용하여 히트 위치에 정확히 이펙트를 배치하세요. PhysicalMaterial에 따라 다른 이펙트를 선택하세요.
심화 과제
undefined