PART 4 - 강의 3/4
콤보 시스템 구현
입력 큐잉과 몽타주 연동 콤보
01
콤보 시스템 아키텍처
컴포넌트 기반 설계
콤보 매니저 컴포넌트
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class UComboManagerComponent : public UActorComponent
{
GENERATED_BODY()
public:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
FOnComboAdvanced, int32, NewComboIndex, int32, MaxCombo);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnComboReset);
UPROPERTY(BlueprintAssignable)
FOnComboAdvanced OnComboAdvanced;
UPROPERTY(BlueprintAssignable)
FOnComboReset OnComboReset;
UFUNCTION(BlueprintCallable)
void AdvanceCombo();
UFUNCTION(BlueprintCallable)
void ResetCombo();
UFUNCTION(BlueprintCallable)
void QueueComboInput();
UFUNCTION(BlueprintCallable)
void OpenComboWindow();
UFUNCTION(BlueprintCallable)
void CloseComboWindow();
UFUNCTION(BlueprintPure)
bool IsComboWindowOpen() const { return bComboWindowOpen; }
UFUNCTION(BlueprintPure)
bool HasQueuedInput() const { return bInputQueued; }
UFUNCTION(BlueprintPure)
int32 GetCurrentComboIndex() const { return CurrentComboIndex; }
protected:
UPROPERTY(EditDefaultsOnly)
int32 MaxComboCount = 3;
UPROPERTY(EditDefaultsOnly)
float ComboResetDelay = 0.5f;
private:
int32 CurrentComboIndex = 0;
bool bComboWindowOpen = false;
bool bInputQueued = false;
FTimerHandle ComboResetTimerHandle;
};
02
콤보 어빌리티
몽타주 기반 콤보 공격
콤보 어빌리티 구현
void UGA_ComboAttack::ActivateAbility(...)
{
if (!CommitAbility(...)) { EndAbility(...); return; }
// 콤보 매니저
AActor* AvatarActor = GetAvatarActorFromActorInfo();
ComboManager = AvatarActor->FindComponentByClass<UComboManagerComponent>();
// 큐잉된 입력 처리
if (ComboManager->HasQueuedInput())
{
ComboManager->AdvanceCombo();
}
int32 ComboIndex = ComboManager->GetCurrentComboIndex();
// 해당 콤보 몽타주 재생
UAnimMontage* MontageToPlay = ComboMontages[ComboIndex];
MontageTask = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(
this, NAME_None, MontageToPlay);
MontageTask->OnCompleted.AddDynamic(this, &UGA_ComboAttack::OnMontageCompleted);
MontageTask->OnCancelled.AddDynamic(this, &UGA_ComboAttack::OnMontageCancelled);
MontageTask->ReadyForActivation();
// 히트 이벤트 대기
UAbilityTask_WaitGameplayEvent* HitTask =
UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
this,
FGameplayTag::RequestGameplayTag(FName("Event.Melee.Hit")));
HitTask->EventReceived.AddDynamic(this, &UGA_ComboAttack::OnMeleeHit);
HitTask->ReadyForActivation();
}
03
콤보 윈도우
애니메이션 노티파이 연동
Anim Notify에서 콤보 윈도우 제어
// 애니메이션 블루프린트에서 Notify 추가:
// 1. AN_OpenComboWindow (공격 중간)
// 2. AN_CloseComboWindow (공격 끝)
// 커스텀 Anim Notify 예제
UCLASS()
class UAnimNotify_OpenComboWindow : public UAnimNotify
{
GENERATED_BODY()
virtual void Notify(USkeletalMeshComponent* MeshComp,
UAnimSequenceBase* Animation) override
{
if (AActor* Owner = MeshComp->GetOwner())
{
if (UComboManagerComponent* ComboMgr =
Owner->FindComponentByClass<UComboManagerComponent>())
{
ComboMgr->OpenComboWindow();
}
}
}
};
// 콤보 윈도우가 열렸을 때 입력이 있으면 큐잉
void AMyCharacter::OnAttackInput()
{
if (ComboManager->IsComboWindowOpen())
{
ComboManager->QueueComboInput();
}
else
{
// 새 콤보 시작
TryActivateAbility(ComboAbilitySpec);
}
}
입력 버퍼링
콤보 윈도우가 열린 동안 입력을 큐잉하면, 현재 공격이 끝나자마자 다음 콤보가 자연스럽게 이어집니다.
SUMMARY
핵심 요약
- ComboManagerComponent로 콤보 상태 관리
- 콤보 윈도우: Anim Notify로 열고 닫기
- 입력 큐잉: 윈도우 중 입력 -> 다음 콤보 예약
- WaitGameplayEvent로 히트 이벤트 감지
- 콤보 인덱스별 다른 몽타주/데미지 적용
04
네트워크 콤보 동기화
멀티플레이어 환경의 콤보 예측과 동기화
C++
// 콤보 인덱스를 서버에서 검증
void UGA_ComboAttack::ServerAdvanceCombo()
{
if (HasAuthority())
{
ComboIndex = FMath::Min(ComboIndex + 1, MaxComboCount - 1);
// 콤보 인덱스를 GameplayEvent로 브로드캐스트
FGameplayEventData EventData;
EventData.EventMagnitude = ComboIndex;
UAbilitySystemBlueprintLibrary::SendGameplayEventToActor(
GetAvatarActorFromActorInfo(),
ComboAdvanceTag,
EventData);
}
}
// 콤보 몽타주는 클라이언트에서 예측 실행
// 서버 검증 실패 시 어빌리티가 취소되어 자동 롤백
콤보 예측 팁
몽타주 재생은 클라이언트에서 예측으로 즉시 시작하되, 데미지 적용은 서버의 WaitGameplayEvent 확인 후에만 수행하세요. GAS의 Prediction Key 시스템이 어빌리티 취소 시 자동으로 이펙트를 롤백합니다.
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: 3단 콤보 어빌리티 구현
UGameplayAbility를 상속하여 3단 콤보 공격을 구현하세요. 각 단계마다 다른 UAnimMontage를 재생하고, AnimNotify로 콤보 윈도우를 열고 닫으세요. UAbilityTask_WaitGameplayEvent로 히트를 감지하세요.
실습 2: 콤보 윈도우와 입력 큐잉
콤보 윈도우가 열린 동안 입력을 버퍼링하고, 현재 몽타주 종료 시 자동으로 다음 콤보로 전환하는 입력 큐잉 시스템을 구현하세요. UAbilityTask_WaitInputPress를 활용하세요.
심화 과제
콤보 인덱스별로 다른 GameplayEffect(데미지 배율, 넉백 크기)를 적용하는 분기형 콤보 시스템을 구현하세요. 마지막 콤보에 특수 피니셔 효과(강화된 GameplayCue와 디버프 GE)를 추가하세요.