내일배움캠프-언리얼

TIL - 81

이시보 2026. 5. 29. 21:38

Element Gauge - GameplayEvent 기반 충전 시스템

한 줄 요약

플레이어가 발생시킨 GameplayEvent(HitSuccess, Parry.Success 등)를 ASC가 받으면, DataTable 기반 룰에 따라 ElementGaugeComponent가 정해진 양만큼 게이지를 충전한다.

왜 DataTable인가

처음엔 컴포넌트 멤버 TMap<FGameplayTag, int32>로 충분하다고 봤지만, 수치 튜닝 빈도가 높을 것으로 예상되어 DataTable로 승격. 향후 행에 추가 컨텍스트(VFX, 사운드, 약점 보너스 배율 등)를 묶기에도 유리.

구조

1. Row 구조체 — FElementChargeRule

USTRUCT(BlueprintType)
struct RETRIEVE_API FElementChargeRule : public FTableRowBase
{
GENERATED_BODY()

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Gauge", meta=(Categories="GameplayEvent"))
FGameplayTag EventTag;

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Gauge", meta=(ClampMin="0"))
int32 ChargeAmount = 0;
};

2. 컴포넌트 멤버

UPROPERTY(EditDefaultsOnly, Category="Gauge|Charge")
TObjectPtr<UDataTable> ChargeRuleTable; // BP에서 DT 할당

TMap<FGameplayTag, int32> ChargeRuleCache; // 런타임 캐시
FGameplayTagContainer SubscribedFilter; // 구독 필터 (해제 시 동일 필터 필요)
FDelegateHandle GameplayEventHandle;

3. 구독 패턴 — AddGameplayEventTagContainerDelegate

GameplayEventHandle = ASC->AddGameplayEventTagContainerDelegate(
SubscribedFilter,
FGameplayEventTagMulticastDelegate::FDelegate::CreateUObject(
this, &UElementGaugeComponent::HandleGameplayEvent));
  • 캐시 키들을 모두 컨테이너에 담아 단일 델리게이트로 구독 → 이벤트당 1회만 발동 (중복 방지)
  • 해제: RemoveGameplayEventTagContainerDelegate(SubscribedFilter, GameplayEventHandle)

4. 핸들러 — 본인 발생 이벤트만 + 정확 매칭

 
void UElementGaugeComponent::HandleGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload)
{
	if (!Payload || Payload->Instigator != GetOwner()) return; // 본인 발생만
	if (const int32* Amount = ChargeRuleCache.Find(EventTag))
	{
		AddCharge(*Amount);
	}
}

핵심 설계 결정

GAS 두 구독 API 비교

"정확 매칭" 정책

  • 테이블에 Attack.HitSuccess.Light가 없고 Attack.HitSuccess만 있을 때, Light 이벤트가 들어오면 → 콜백은 발동(필터 부모 매칭)하지만 캐시 lookup에서 Light가 없어 skip
  • 부모 fallback 안 함. Light/Heavy/WeakPoint 각각 다른 값으로 튜닝하려면 모두 행으로 등록

Instigator 가드

  • 컨벤션: 이벤트 발사 측이 EventData.Instigator = GetOwner() 세팅 (EnemyCombatComponent, PatternCounterComponent 등 기존 코드 따름)
  • 핸들러에서 Payload->Instigator != GetOwner() 면 스킵 → 피격, 보스 패턴 등이 잘못 게이지를 채우지 않음
  • 주의: 신규 이벤트 발사 코드 작성 시 Instigator 반드시 세팅. 누락 시 게이지가 안 오름

바인딩 시점

  • SovereignCharacter::InitializeAbilitySystem()에서 ASC 준비 완료 후 ElementGaugeComponent->BindToASC() 호출
  • EndPlay에서 UnbindFromASC() 자동 해제 (Owner ASC 유효 시 RemoveDelegate)

데이터테이블 만들기

  1. 콘텐츠 브라우저 우클릭 → Miscellaneous → Data Table
  2. Row Structure: ElementChargeRule 선택
  3. 행 추가
  4. BP_SovereignCharacter → Components → ElementGaugeComponent → Details의 Gauge | Charge → Charge Rule Table에 DT 할당

트러블슈팅

  • 게이지가 안 오름 → ① DT가 BP에 할당됐는지 ② 이벤트 발사 측에서 Instigator 세팅했는지 ③ BindToASC가 호출됐는지 (DT 미할당이면 no-op) ④ 캐시에 정확 일치 태그 행이 있는지
  • 두 번 오름  Instigator 가드 누락된 이벤트인지, 또는 같은 이벤트가 두 곳에서 발사되는지 확인

'내일배움캠프-언리얼' 카테고리의 다른 글

TIL - 83  (0) 2026.06.02
TIL - 82  (0) 2026.06.01
TIL - 80  (0) 2026.05.27
TIL - 79  (0) 2026.05.26
TIL - 78  (0) 2026.05.21