[Game Ability System]으로 키보드/마우스 눌렀을 때 바운딩하기 또는 어빌리티 부르는 방법, 어빌리티 시스템과 함께 쓰는 모듈들을 함께 정리해보려고 합니다.
1. GAS의 핵심 구성 요소
GAS는 여러 시스템이 유기적으로 연결된 구조입니다.
(1). Gameplay Ability / (GA)
" 행동을 정의하는 클래스 "
🔹핵심 함수
- ActivateAbility()
- EndAbility()
- CommitAbility()
(2). AttributesSet(AS) / Curve Data
" 체력. 마나, 공격력 같은 수치를 담당하는 클래스 "
Attribute변경은 직접 하지 않고 GameplayEffect를 통해서만 변경하는 것이 정석 구조입니다.
(3). ASC (UAbilitySystemComponent)
" GAS의 실제 핵심 관리자 클래스"
주의 AbilitySpec는 ASC가 아님
(4). Gameplay Effect / GE
" 수치/상태/ 지속효과 담당 클래스 "
(5). Gameplay Tags
" 상태를 표현하는 라벨 시스템 "
🔹특징
- Tag는 단순 bool 값이 아닙니다. 태그는 내부적으로 "Count"를 가집니다. (정확히는 ASC 내부적으로 FGameplayTagCountContainer를 가진다)
- 같은 태그가 여러 GE에 의해 적용되면 Count가 누적됩니다.
(6). GameplayCue
" 이펙트/사운드 같은 시각적 요소 담당 "
2. 기본 세팅
(1). 플러그인/ 모듈 켜기
- GameplayAbilities
- GameplayTags
- GameplayTasks
Build.cs에도 추가 필요합니다.
(2) ASC 세팅하기
GAS를 쓰려면 상호작용 액터가 ASC를 가지거나 다른 액터의 ASC에 접근 가능하도록 세팅해야 합니다.
UAbilitySystemComponent* AbilitySystemComponent;
보통 Character에 두고 사용합니다.
3. 입력 바인딩 -> Ability 실행
※ 핵심 : BindAction 할 때 Func가 '태그'를 알고 'ASC'로 전달해야 합니다.
(1). BindAction으로 태그와 실행시킬 함수 바인딩 시켜줍니다.
FEnhancedInputActionEventBinding& BindAction(const UInputAction* Action, ETriggerEvent TriggerEvent, UObject* Object, FName FunctionName)
(2) InputAction->Tag 맵으로 넘김

● GetActivatableAbilities( )
ASC 내부에는 [ GetActivatableAbilities( ) ] 함수가 존재합니다. 이 함수는 현재 ASC에 등록된 AbilitySpec 목록을 반환합니다. 콘솔에서 [ 키보드(') + 넘버패드(3) ]]으로 확인되는 부여된 어빌리티 리스트도 이 목록을 기반으로 출력됩니다.
● TryActivateAbility(AbilitySpec.Handle)
해당 어빌리티를 활성하려고 시도하고, 실패하면 return false 합니다. 어빌리티 인스턴스를 activate 상태로 진입시키는 것입니다. GameplayAbility라면 ActivateAbility -> 커밋/코스트/쿨다운/태스크/입력 상태/ 네트워크 권한 같은 걸 체크합니다.
* AbilitySpec.Handle : 활성화할 어빌리티 스펙을 식별하는 핸들 ID

● Commit
- CommitAbility()
- TryActivateAbility()는 "활성화 시도"일 뿐이고, 쿨다운/코스트를 실제로 적용하는 건 Commit 시점입니다.
- Cost만 Cooldown만 따로따로 처리하고 싶다면,
- CommitAbilityCost()만 실행
- CommitAbilityCooldown()만 실행
- CommityAbility는 자동이 아니라 개발자가 ActivateAbility안에서 호출해야 합니다. Ability를 만들었는데 Commit을 안 하면 아래와 같은 상황이 됩니다.
- 쿨타임 안 걸림
- 코스트 안 빠짐
- 태그 안 붙음

4. Ability 쿨타임(Cooldown), 코스트(Cost), 버프/디버프/도트/, 태그 부여/차단 등등... 상태/수치/지속효과 주기
✅예시
(1). 쿨타임(Cooldown) GamplayEffect 생성하기
- GE_Cooldown_XXX 같은 GameplayEffect(Blueprint/Class) 생성
- Duration Policy (이 GE(GameEffect)가 얼마나 오래 살아 있나?)
- [ Instant ] : 일시적인 적용되는 순간 한 번만 실행되고 바로 끝남.
- [ Has Duration ] : 정해진 시간 동안 유지되다가 만료 <- 쿨타임은 Has Duration
- [ Infinite ] : 직접 제거할 때까지 시간제한 없이 계속 유지
- Duration Magnitude = 쿨다운 시간(예: 5.0s)
- Granted Tags에 Cooldown.Ability.XXX 같은 태그 추가 → 이 태그가 “쿨다운 중임”을 표시

(2) Ability에서 GameplayEffect를 지정해 주기

(3) 실제로 쿨다운 적용하기 위해서 함수 실행해 주기
- CommitAbility()
- TryActivateAbility()는 "활성화 시도"일 뿐이고, 쿨다운/코스트를 실제로 적용하는 건 Commit 시점입니다.
- 정확히는 CommitAbility 호출 시 내부적으로 ApplyCooldown()이 실행된다.
(4) 쿨다운이 끝나고 나서 이벤트 처리 하기
Cooldown이 끝났다고 해서 GAS가 TryActivateAbility()를 자동으로 호출하지는 않습니다. 어빌리티와 GameplayEffect는 별개의 동작이라고 생각할 수 있습니다.
만약 쿨다운이 끝나고 나서하고 싶은 동작이 있다면? "쿨다운 태그 제거"를 감지할 수 있기 때문에 탱크의 변화로 로직을 이어서 짜야합니다. 태그 변화는 GameplayTag 이벤트 Delegate로 잡을 수가 있습니다.
위 (1) 번에서 지정한 쿨 타임 태그가 쿨타임이 끝나고 사라지게 됩니다. 이를 감지해서 이벤트를 발생시킬 수 있습니다.
아래는 태그의 변화를 지켜보는 함수를 만들었습니다.
void UWarriorAbilitySystemComponent::StartListenTag(const FGameplayTag Tag)
{
if (!Tag.IsValid())
{
return;
}
// 중복 바인딩 방지
if (TagEventHandles.Contains(Tag))
{
return;
}
FDelegateHandle Handle =
RegisterGameplayTagEvent(Tag, EGameplayTagEventType::NewOrRemoved)
.AddUObject(this, &UWarriorAbilitySystemComponent::HandleTagChanged);
TagEventHandles.Add(Tag, Handle);
}
- [ RegisterGameplayTagEvent ] : ASC가 내부적으로 관리하는 태그 카운트를 감시하는 이벤트를 가져옵니다.
- 가져온 델리게이트에 직접 함수를 바인딩해줍니다.
- 그렇게 되면 Tag에 연결한 태그가 NewOrRemoved 이벤트가 발생할 때 저장해(바인딩해) 둔 함수를 호출합니다.
- 결과적으로 AddUObject는 "내가 추가한 바인딩"을 식별하는 핸들을 돌려줍니다 (핸들을 저장해 주는 이유는 나중에 어떤 바인딩을 지울지 특정하기가 어렵기 때문입니다)
이렇게 바인딩 한 함수 HandleTagChanged 안에 Delegate를 BroadCast 해줍니다.
void UWarriorAbilitySystemComponent::HandleTagChanged(FGameplayTag Tag, int32 NewCount)
{
// (선택) 태그 카운트 변화 전체 방송
OnTagCountChangedBP.Broadcast(Tag, NewCount);
// "완전히 없어짐"만 따로 방송
if (NewCount == 0)
{
OnTagRemovedBP.Broadcast(Tag);
}
}
※ BP에서 OnTagRemoveBP 이벤트를 Bind를 해주면 Broadcast 하면 원하는 이벤트를 실행시킬 수 있습니다.
근데 ★ 주의할 점 ★ 저는 GameplayEffect에 등록한 GameplayCue가 파라미터도 지정해야 하고, Cooldown동안 이펙트를 유지해줘야 하는 상황이었습니다. 이 때문에 Ability에서 AddCue를 해주고 Cooldown이 끝날 때 RemoveCue를 실행해줘야 하는 상황입니다. 여기서 Ability는 대부분 Cooldown동안 살아있지 않도록 개발합니다. 그래서 Ability안에서 OnTagRemoveBP를 바인딩하게 되면, 그 Ability는 이미 endAbility 되었기 때문에 실행되지 않습니다. 오랫동안 살아 있는 ASC나 Chacter에 넣는 게 바람직할 거 같습니다.
추가로, 저는 ASC 안에 Tag를 지켜보는 함수를 만들었지만, GPT에게 물어보니 ActorComponent로 만들어서 태그 제거 감지 리스너를 만들어주는 게 가장 깔끔한 방법이라고 합니다.😊
※ 쿨다운이 끝난 게 적용한 Ability의 EndAbility()를 실행하는 것이 아닙니다. 어빌리티가 끝나는 것과는 독립적입니다.
'🎯 game engine > ◽ 언리얼(unreal)' 카테고리의 다른 글
| [Unreal / C++] AAA급 UI 만들기 ControlTab - IInputProcessor 이용하여 키 변경하기 + AddTicker 사용하는 이유 (2) | 2026.03.16 |
|---|---|
| [Unreal] Behavior Tree 이해하면서 몬스터 AI 만들기 (0) | 2025.12.02 |
| [Unreal / C++] AAA Frontend UI/Menu 만들기 (프레임 워크 정리 + 델리게이트, 서브시스템) (1) | 2025.11.20 |
| [Unreal] UI 세팅/구조 분석 (Set Up Common UI) (7) | 2025.09.16 |
| [Unreal] Frontend UI Subsystem (2) | 2025.09.14 |
존잘 프로그래머가 되고싶어