어빌리티 활성화 흐름
TryActivateAbility부터 EndAbility까지의 전체 시퀀스
활성화 시퀀스 개요
클라이언트 예측 어빌리티의 전체 흐름
1. 클라이언트: TryActivateAbility() 호출
|
2. InternalTryActivateAbility() 호출
|
3. CanActivateAbility() 검사
- 태그 요구사항 확인
- 비용(Cost) 확인
- 쿨다운 확인
- 활성 인스턴스 확인
|
4. Prediction Key 생성 후 CallServerTryActivateAbility() 호출
|
5. 서버 응답 전에 CallActivateAbility() 호출 (예측 실행)
|
6. PreActivate() -> ActivateAbility() 순차 호출
|
7. 서버 검증 결과에 따라:
- 성공: 계속 진행
- 실패: ClientActivateAbilityFailed() 호출 -> 롤백
LocalPredicted 어빌리티는 서버 응답을 기다리지 않고 즉시 실행합니다. 서버가 거부하면 모든 예측된 변경사항이 롤백됩니다.
CanActivateAbility 검사
어빌리티 활성화 전 검증 단계
태그 요구사항
ActivationRequiredTags 보유, ActivationBlockedTags 미보유, 소스/타겟 태그 조건 확인
비용 검사
CostGameplayEffect로 정의된 어트리뷰트 비용 충족 여부 (마나, 스태미나 등)
쿨다운 검사
CooldownGameplayEffect로 부여된 쿨다운 태그의 활성 여부 확인
인스턴스 검사
Instancing Policy에 따른 동시 활성화 가능 여부, 이미 활성 상태인지 확인
// GameplayAbility에서 설정
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer ActivationOwnedTags; // 활성화 시 부여할 태그
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer ActivationRequiredTags; // 필수 태그 (모두 있어야 함)
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer ActivationBlockedTags; // 차단 태그 (하나라도 있으면 불가)
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer CancelAbilitiesWithTag; // 이 태그 가진 어빌리티 취소
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer BlockAbilitiesWithTag; // 이 태그 가진 어빌리티 차단
ActivateAbility 구현
어빌리티 로직의 핵심 진입점
void UMyGameplayAbility::ActivateAbility(
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
const FGameplayEventData* TriggerEventData)
{
// 권한 또는 예측 키가 있는지 확인
if (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo))
{
// 비용과 쿨다운 커밋
if (!CommitAbility(Handle, ActorInfo, ActivationInfo))
{
EndAbility(Handle, ActorInfo, ActivationInfo, true, true);
return;
}
// 어빌리티 로직 실행
PerformAbilityAction();
}
// 중요: EndAbility 호출은 개발자 책임!
}
모든 어빌리티는 반드시 EndAbility()를 호출해야 합니다. 호출하지 않으면 어빌리티가 영원히 활성 상태로 남아 리소스 누수와 버그를 유발합니다.
CommitAbility 분해
비용과 쿨다운을 적용하는 핵심 함수
// CommitAbility() = CommitCost() + CommitCooldown()
bool UGameplayAbility::CommitAbility(
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
FGameplayTagContainer* OptionalRelevantTags)
{
// 1. 비용 적용 (마나 소모 등)
if (!CommitAbilityCost(Handle, ActorInfo, ActivationInfo, OptionalRelevantTags))
{
return false;
}
// 2. 쿨다운 적용
if (!CommitAbilityCooldown(Handle, ActorInfo, ActivationInfo, false, OptionalRelevantTags))
{
return false;
}
return true;
}
// 비용만 따로 적용하고 싶을 때
bool CommitAbilityCost(...);
// 쿨다운만 따로 적용하고 싶을 때
bool CommitAbilityCooldown(...);
// 적용 없이 검사만 하고 싶을 때
bool CheckCost(...);
bool CheckCooldown(...);
- CheckCost -> PerformAction -> CommitCost: 액션 성공 시에만 비용 소모
- CommitCost -> ... -> CommitCooldown: 차징 완료 시 쿨다운 시작
- CommitAbility 생략: 패시브 어빌리티 (비용/쿨다운 없음)
EndAbility 처리
어빌리티 정리와 종료 플래그
void UMyGameplayAbility::EndAbility(
const FGameplayAbilitySpecHandle Handle,
const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo,
bool bReplicateEndAbility,
bool bWasCancelled)
{
// 정리 로직
// - 활성 태스크 종료
// - 임시 GameplayEffect 제거
// - 델리게이트 언바인드
// 부모 호출 필수!
Super::EndAbility(Handle, ActorInfo, ActivationInfo,
bReplicateEndAbility, bWasCancelled);
}
// 종료 파라미터:
// bReplicateEndAbility: true면 네트워크로 종료 복제
// bWasCancelled: true면 외부에서 취소됨 (vs 정상 완료)
| 종료 방식 | bReplicateEndAbility | bWasCancelled |
|---|---|---|
| 정상 완료 | true | false |
| 외부 취소 (다른 어빌리티에 의해) | true | true |
| 로컬 전용 종료 | false | false |
| 서버 거부로 인한 실패 | true | true |
핵심 요약
- 활성화 시퀀스: TryActivate -> CanActivate -> PreActivate -> ActivateAbility
- CanActivateAbility: 태그, 비용, 쿨다운, 인스턴스 조건 검사
- CommitAbility = CommitCost + CommitCooldown (분리 호출 가능)
- EndAbility 호출 필수 - 미호출 시 리소스 누수
- 클라이언트 예측 시 서버 거부 -> 롤백 처리
도전 과제
배운 내용을 직접 실습해보세요
GiveAbility()로 어빌리티를 부여하고 TryActivateAbilityByClass()로 활성화하세요. CanActivateAbility(), ActivateAbility(), EndAbility()의 호출 순서를 로그로 확인하세요.
AbilityTags, BlockAbilitiesWithTag, ActivationBlockedTags를 설정하여 특정 상태에서 어빌리티가 차단되는 시스템을 구현하세요.
undefined