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)를 추가하세요.