PART 4 - 강의 4/4

차징/채널링 어빌리티

버튼 홀드와 시간 기반 어빌리티

01

InputReleased 오버라이드

버튼 릴리즈 감지

차징 어빌리티 기본 구조 UCLASS() class UGA_ChargedShot : public UGameplayAbility { GENERATED_BODY() public: UGA_ChargedShot(); protected: virtual void ActivateAbility(...) override; // 버튼 릴리즈 시 호출 virtual void InputReleased( const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo) override; UFUNCTION() void OnChargeComplete(float ChargeTime); protected: UPROPERTY(EditDefaultsOnly) float MaxChargeTime = 2.0f; UPROPERTY(EditDefaultsOnly) float MinDamageMultiplier = 1.0f; UPROPERTY(EditDefaultsOnly) float MaxDamageMultiplier = 3.0f; private: UPROPERTY() UAbilityTask_WaitForCharge* ChargeTask; };
02

차징 구현

시간에 따른 데미지 증가

차징 어빌리티 구현 void UGA_ChargedShot::ActivateAbility(...) { if (!CommitAbility(...)) { EndAbility(...); return; } // 차지 몽타주 재생 if (ChargeMontage) { UAbilityTask_PlayMontageAndWait* MontageTask = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy( this, NAME_None, ChargeMontage); MontageTask->ReadyForActivation(); } // 차지 Task 시작 ChargeTask = UAbilityTask_WaitForCharge::CreateTask( this, MaxChargeTime); ChargeTask->OnChargeComplete.AddDynamic( this, &UGA_ChargedShot::OnChargeComplete); ChargeTask->ReadyForActivation(); // 차지 시작 GameplayCue FGameplayCueParameters CueParams; CueParams.Location = GetAvatarActorFromActorInfo()->GetActorLocation(); K2_ExecuteGameplayCue( FGameplayTag::RequestGameplayTag(FName("GameplayCue.Ability.ChargeStart")), CueParams); } void UGA_ChargedShot::InputReleased(...) { // 버튼을 놓으면 차지 완료 if (ChargeTask) { ChargeTask->CompleteCharge(); } } void UGA_ChargedShot::OnChargeComplete(float ChargeTime) { float ChargePercent = FMath::Clamp(ChargeTime / MaxChargeTime, 0.f, 1.f); float DamageMultiplier = FMath::Lerp( MinDamageMultiplier, MaxDamageMultiplier, ChargePercent); // 발사 로직 FireShot(DamageMultiplier); EndAbility(...); }
03

채널링 어빌리티

지속 효과 발동

채널링 구현 void UGA_ChanneledBeam::ActivateAbility(...) { if (!CommitAbilityCost(...)) { EndAbility(...); return; } // 채널링 중 마나 소모 Effect (Periodic) ApplyGameplayEffectToOwner(..., ManaDrainEffect, ...); // 빔 스폰 SpawnBeamActor(); // 주기적 데미지 Task UAbilityTask_Repeat* RepeatTask = UAbilityTask_Repeat::RepeatAction( this, 0.1f, -1); // 0.1초 간격, 무한 RepeatTask->OnPerformAction.AddDynamic( this, &UGA_ChanneledBeam::OnChannelTick); RepeatTask->ReadyForActivation(); // 입력 릴리즈 대기 UAbilityTask_WaitInputRelease* ReleaseTask = UAbilityTask_WaitInputRelease::WaitInputRelease(this); ReleaseTask->OnRelease.AddDynamic( this, &UGA_ChanneledBeam::OnInputReleased); ReleaseTask->ReadyForActivation(); } void UGA_ChanneledBeam::OnChannelTick(int32 ActionNumber) { // 빔 라인트레이스 FHitResult Hit; if (PerformBeamTrace(Hit)) { // 타겟에 데미지 ApplyDamageToTarget(Hit.GetActor()); } // 마나 체크 if (GetMana() <= 0) { EndAbility(...); } } void UGA_ChanneledBeam::OnInputReleased(float TimeHeld) { EndAbility(...); }
채널링 취소 조건

채널링은 입력 릴리즈, 마나 소진, 스턴 등 여러 조건으로 취소될 수 있습니다. 태그 기반 취소 조건을 활용하세요.

SUMMARY

핵심 요약

  • InputReleased() 오버라이드로 버튼 릴리즈 감지
  • 차징: 시간에 비례한 데미지 배율
  • 채널링: Periodic Effect로 지속 비용 소모
  • WaitInputRelease Task로 입력 종료 대기
  • GameplayCue로 차지/채널 시각 피드백
04

차징 레벨과 GE 연동

차징 단계별 GameplayEffect 적용

C++ // 차징 레벨에 따른 GE 선택 void UGA_ChargeAttack::ReleaseCharge() { float ChargeRatio = CurrentChargeTime / MaxChargeTime; int32 ChargeLevel = FMath::Clamp( FMath::FloorToInt(ChargeRatio * 3), 0, 2); FGameplayEffectSpecHandle SpecHandle = MakeOutgoingGameplayEffectSpec( ChargeLevelEffects[ChargeLevel], ChargeLevel + 1); // SetByCaller로 차징 배율 전달 SpecHandle.Data->SetSetByCallerMagnitude( DamageMultiplierTag, 1.f + ChargeRatio * 2.f); ApplyGameplayEffectSpecToTarget( GetCurrentAbilitySpecHandle(), GetCurrentActorInfo(), GetCurrentActivationInfo(), SpecHandle, TargetData); }
네트워크 차징 주의

차징 시간은 서버에서 계산하세요. 클라이언트의 CurrentChargeTime을 신뢰하면 조작 가능합니다. WaitInputRelease Task 완료 시 서버에서 최종 차징 레벨을 결정하세요.

PRACTICE

도전 과제

배운 내용을 직접 실습해보세요

실습 1: 3단계 차징 어빌리티

UAbilityTask_WaitInputRelease로 버튼 릴리즈를 감지하고, 차징 시간에 따라 약/중/강 3단계로 구분하세요. 각 단계에서 다른 UAnimMontage와 GameplayCue를 실행하세요.

실습 2: 채널링 빔 어빌리티

InputReleased()를 오버라이드하여 버튼 홀드 동안 지속되는 빔을 구현하세요. Periodic GE로 0.5초마다 마나를 소모하고, 마나 부족 시 CancelAbility()로 자동 종료하세요.

심화 과제

차징 중 GameplayCue로 시각 피드백(파티클 크기 증가, 색상 변화)을 구현하고, SetByCaller Magnitude로 차징 배율을 GE에 전달하세요. 오버차징 시 자기 데미지를 주는 리스크 시스템도 추가하세요.