Post

2026-06-19 TIL (80일차)

2026-06-19 TIL (80일차)

[UE5 GAS] 어빌리티 태그(Ability Tags) 설정


1. 어빌리티의 정체성 (Identity)

🔹 AssetTags (Default AbilityTags)

  • 의미: 이 어빌리티 자체가 가지고 있는 ‘명함(정체성)’입니다.
  • 언제 사용하나요? 이 능력이 어떤 부류인지 정의할 때 씁니다.
    • 예시: 파이어볼 스킬이라면 Ability.Skill.Magic.Fire 라는 태그를 달아줍니다. 나중에 “불 속성 스킬의 데미지를 10% 올린다” 같은 로직을 짤 때 이 태그를 찾아 적용합니다.

2. 다른 어빌리티와의 상호작용 (Interaction)

🔹 Cancel Abilities with Tag

  • 의미: 이 어빌리티가 실행되는 순간, 여기에 등록된 태그를 가진 ‘현재 실행 중인 다른 어빌리티’들을 강제로 취소(중단)시켜 버립니다.
  • 언제 사용하나요? 더 강력한 행동이나 긴급한 행동으로 기존 행동을 덮어씌울 때 씁니다.
    • 예시: ‘회피(Dash)’ 어빌리티를 실행할 때, 공격 중이거나 포션 마시는 모션을 즉시 캔슬해야 하므로 여기에 Ability.Attack, Ability.Item 태그를 넣습니다.

🔹 Block Abilities with Tag

  • 의미: 이 어빌리티가 실행되고 있는 동안, 여기에 등록된 태그를 가진 다른 어빌리티가 아예 ‘시작(발동)’되지 못하게 막습니다. (Cancel은 이미 실행 중인 걸 끄는 것이고, Block은 새로 켜지는 걸 막는 것입니다.)
  • 언제 사용하나요? 특정 행동 중에는 다른 짓을 못하게 묶어둘 때 씁니다.
    • 예시: ‘기 모으기(차징)’ 스킬을 쓰는 도중에는 이동이나 기본 공격을 하면 안 되므로, 여기에 Ability.Movement, Ability.Attack 태그를 넣어 차단합니다.

3. 실행 중 시전자에게 부여되는 상태 (Granted State)

🔹 Activation Owned Tags

  • 의미: 이 어빌리티가 실행 중인 동안, 시전자(Owner)에게 이 태그를 임시로 부여합니다. 어빌리티가 끝나면 이 태그도 자동으로 사라집니다.
  • 언제 사용하나요? 스킬 시전 중 캐릭터의 일시적인 ‘상태(State)’를 정의할 때 씁니다.
    • 예시: ‘구르기’ 어빌리티를 쓰는 1초 동안 캐릭터에게 State.Invincible(무적) 태그를 부여하여 피해를 입지 않게 만듭니다.

4. 시전자(Owner)의 발동 조건 (Owner Conditions)

🔹 Activation Required Tags

  • 의미: 시전자(내 캐릭터)가 여기에 등록된 태그를 가지고 있어야만 이 어빌리티를 실행할 수 있습니다.
  • 언제 사용하나요? 특정 버프나 조건이 충족되었을 때만 나가는 스킬을 만들 때 씁니다.
    • 예시: 분노 게이지가 꽉 차서 State.Enraged 태그를 가진 상태에서만 쓸 수 있는 궁극기.

🔹 Activation Blocked Tags

  • 의미: 시전자(내 캐릭터)가 여기에 등록된 태그를 하나라도 가지고 있다면 이 어빌리티를 실행할 수 없습니다. (가장 많이 쓰이는 핵심 기능!)
  • 언제 사용하나요? 상태 이상에 걸렸을 때 행동을 제어하기 위해 씁니다.
    • 예시: 모든 공격 스킬에 State.Stun(기절), State.Dead(사망), State.Silence(침묵) 태그를 넣어두면, 기절했을 때 스킬이 나가는 버그를 방지할 수 있습니다.

5. 이벤트 발생처(Source) 및 대상(Target)의 발동 조건

(주로 Gameplay Event로 어빌리티를 트리거하거나 타겟팅 시스템을 쓸 때 사용됩니다.)

🔹 Source Required Tags / Source Blocked Tags

  • 의미: 이 어빌리티를 촉발시킨 ‘원인(Source)’ 객체가 특정 태그를 가지고 있어야 하거나(Required), 없어야만(Blocked) 실행됩니다.
  • 언제 사용하나요? 누가 나에게 이벤트를 보냈는지에 따라 어빌리티 발동 여부를 결정할 때 씁니다.

🔹 Target Required Tags / Target Blocked Tags

  • 의미: 이 어빌리티가 적용될 ‘대상(Target)’이 특정 태그를 가지고 있어야 하거나(Required), 없어야만(Blocked) 실행됩니다.
  • 언제 사용하나요? 스킬이 들어갈 대상을 필터링할 때 씁니다.
    • Target Required 예시: 힐링 스킬은 타겟이 Team.Friendly(아군) 태그를 가졌을 때만 써집니다.
    • Target Blocked 예시: 대상이 이미 State.Dead(사망) 태그를 가지고 있거나 State.Invincible(무적) 태그를 가지고 있다면 타겟팅 스킬이 발동되지 않도록 막습니다.

요약

  • Asset Tags: 내 스킬은 어떤 종류인가?
  • Cancel / Block: 내 스킬을 쓰면, 남의 스킬을 끄거나(Cancel) 못 켜게 막을까(Block)?
  • Owned: 내 스킬을 쓰는 동안 나는 어떤 상태(무적 등)가 되는가?
  • Required / Blocked: 내가 어떤 상태일 때 이 스킬이 켜지고(Required), 어떤 상태면 절대 안 켜질까(Blocked)?



[UE5 GAS] 어빌리티 인스턴싱 정책 (Instancing Policy)

이 설정은 “이 스킬을 사용할 때 메모리에 객체(Instance)를 어떻게 올릴 것인가?”를 결정합니다. 성능(최적화)과 블루프린트 노드 사용 가능 여부에 직결되는 매우 중요한 옵션입니다.


1. Non Instanced (인스턴스 생성 안 함)

  • 의미: 스킬이 발동될 때 어빌리티 객체를 메모리에 새로 만들지 않습니다. 언리얼 엔진이 미리 만들어둔 기본 껍데기(CDO, Class Default Object)를 그대로 가져다 씁니다.
  • 특징: * 메모리 소모와 생성 비용이 0에 가까워 성능상 가장 유리합니다.
    • 단점: 객체가 없으므로 변수를 저장할 수 없고, ‘Delay’나 ‘Wait’ 같은 지연(Latent) 노드, 비동기 태스크(Async Task)를 절대 사용할 수 없습니다.
  • 언제 사용하나요?
    • 변수를 저장할 필요 없이 순간적으로 딱 한 번 실행되고 끝나는 아주 단순한 로직에 사용합니다.
    • 주로 C++로 하드코딩된 패시브 스킬이나, 단순히 데미지만 틱(Tick) 주고 끝나는 기본 계산용 어빌리티에 적합합니다. (블루프린트에서는 거의 쓰지 않습니다.)

2. Instanced Per Actor (액터당 하나의 인스턴스) -> 가장 많이 씀

  • 의미: 캐릭터(Actor)가 이 스킬을 처음 배울 때(Granted), 해당 액터 전용으로 딱 하나의 어빌리티 객체를 메모리에 만듭니다. 이후 스킬을 쓸 때마다 새로 만들지 않고, 처음 만들어둔 그 객체를 계속 재사용합니다.
  • 특징:
    • 블루프린트에서 변수를 만들고 값을 저장할 수 있습니다.
    • ‘Play Montage and Wait’나 ‘Delay’ 같은 지연/비동기 노드를 완벽하게 사용할 수 있습니다.
    • 매번 새로 생성하지 않으므로 성능과 기능의 밸런스가 가장 좋습니다.
  • 언제 사용하나요?
    • GAS 스킬 제작 시 기본값(Default)이자 가장 추천하는 옵션입니다.
    • 플레이어의 콤보 공격, 파이어볼 발사, 구르기, 버프 등 대부분의 일반적인 스킬 구현에 널리 사용됩니다.

3. Instanced Per Execution (실행할 때마다 새로운 인스턴스)

  • 의미: 스킬 버튼을 눌러 발동(Execution)할 때마다 매번 새로운 어빌리티 객체를 메모리에 새로 찍어냅니다.
  • 특징:
    • 똑같은 스킬을 1초에 10번 쓰면 메모리에 10개의 독립적인 어빌리티 객체가 동시에 돌아갑니다.
    • 단점: 매번 스폰하고 지우는 과정(Garbage Collection)이 발생하므로 성능 소모가 가장 심합니다. 최적화의 적입니다.
  • 언제 사용하나요?
    • 동일한 스킬이 동시에 여러 번 겹쳐서 실행되어야 하고, 각각이 서로 다른 변수 값(상태)을 유지해야 할 때만 제한적으로 씁니다.
    • 예시: 연사력이 엄청나게 빠른 기관총 스킬. 총알이 날아가는 궤적이나 데미지 연산을 어빌리티 내부에서 처리하는데, 1번 총알과 2번 총알의 로직이 동시에 겹쳐서 돌아가야 할 때 사용합니다.

요약 비교표

정책 (Policy)메모리/성능 비용변수 저장 및 Wait 노드 사용다중 겹침 실행추천 사용처
Non Instanced매우 낮음 (최고)❌ 불가능❌ 불가능극히 단순한 즉발형 C++ 패시브
Instanced Per Actor보통 (밸런스형)⭕️ 가능❌ 불가능 (보통 막음)거의 모든 일반적인 스킬 (기본값)
Instanced Per Exec..매우 높음 (주의)⭕️ 가능⭕️ 가능여러 번 중첩해서 돌아가야 하는 스킬

팁: 특별한 이유가 없다면 무조건 Instanced Per Actor로 설정하고 블루프린트 로직을 작성하는 것이 안전하고 효율적입니다.




⚙️ [UE5 GAS] 어빌리티 핵심 설정 (메모리, 네트워크, 보안)

언리얼 엔진의 GAS(Gameplay Ability System)에서 어빌리티를 생성할 때 디테일 패널에서 설정해야 하는 핵심 항목들입니다. 이 설정들은 멀티플레이어 환경에서의 최적화, 스킬의 작동 방식, 그리고 해킹 방지(보안)를 결정하는 뼈대가 됩니다.


1부: 인스턴싱 및 상태 제어 (Instancing & State)

1. 리플리케이션 정책 (Replication Policy)

“이 스킬의 내부 상태(데이터)를 서버와 다른 유저들에게 공유할 것인가?”

멀티플레이 게임에서 내 캐릭터가 스킬을 썼을 때, 그 스킬 객체(Instance) 자체가 네트워크를 타고 서버와 다른 클라이언트에게 복제(Replication)될지 결정합니다.

  • Do Not Replicate (복제 안 함): 싱글플레이 게임이거나, 스킬 내부에 중요한 변수를 저장하지 않고 애니메이션/이펙트만 재생하고 끝나는 가벼운 스킬에 사용합니다. (네트워크 부하가 가장 적음)
  • Replicate (복제함): 스킬 내부에 ‘현재 모은 기(차징 수치)’ 같은 중요한 변수가 있고, 이 변수를 서버나 다른 유저들도 실시간으로 알아야 할 때 설정합니다. (단, 인스턴싱 정책이 Instanced일 때만 유효함)

2. 인스턴싱 정책 (Instancing Policy)

“이 스킬을 실행할 때마다 메모리(도화지)를 어떻게 배정할 것인가?”

스킬 내부에 변수를 저장할 수 있는지, 딜레이 노드를 쓸 수 있는지 결정하는 메모리 할당 정책입니다.

  • Non Instanced: 메모리 할당 없음. 가장 가볍지만 변수 저장 및 딜레이 노드 사용 불가. (주로 수치 계산용 기본 스킬)
  • Instanced Per Actor: 캐릭터당 1개만 할당해서 평생 재활용. 변수 저장 및 지연 노드 사용 가능. (가장 흔하게 쓰이는 기본값)
  • Instanced Per Execution: 실행할 때마다 메모리 무한 생성. 겹쳐 쓰기 가능하지만 성능 소모가 심함. (다중 디버프, 연속 트랩 등에 제한적으로 사용)

3. 서버에서 원격 어빌리티 취소 준수 (Server Respects Remote Ability Cancellation)

“유저(클라이언트)가 ‘나 이 스킬 취소할래!’ 했을 때, 서버가 군말 없이 들어줄 것인가?”

클라이언트 측에서 스킬을 강제로 끊는 신호를 서버로 보냈을 때의 서버 반응을 결정합니다.

  • 체크 (기본값): 유저가 버튼을 뗐을 때 즉각적으로 취소되어야 조작감이 좋은 스킬(예: 달리기, 조준)에 사용합니다. 클라이언트의 취소 요청을 서버가 즉시 수용합니다.
  • 체크 해제: 핵(Hack) 유저가 억지로 후딜레이를 캔슬하는 것을 막아야 하거나, 서버가 절대적인 통제권을 가져야 하는 중요한 궁극기 등에 사용합니다. 클라이언트가 취소 요청을 해도 서버가 조건을 따져 무시할 수 있습니다.

4. 인스턴스드 어빌리티 다시 트리거 (Retrigger Instanced Ability)

“스킬이 이미 켜져 있는데 또 실행 버튼을 누르면, 처음부터 다시 시작할 것인가?”

인스턴싱 정책이 Instanced Per Actor일 때 작동하며, 실행 중인 스킬의 단축키를 다시 눌렀을 때의 반응을 정합니다.

  • 체크: 기존에 돌아가던 스킬을 강제로 끄고(End Ability), 처음부터 다시 실행(Retrigger)합니다. 타이밍에 맞춰 처음부터 타격 판정이 다시 발생해야 하는 ‘연속 베기(콤보)’ 스킬 등에 사용합니다.
  • 체크 해제 (기본값): 새로운 입력을 무시합니다. 캐스팅 스킬 도중 버튼을 한 번 더 눌렀다고 캐스팅이 0초로 초기화되는 것을 막아줍니다.

2부: 네트워크 동기화 및 보안 (Network & Security)

1. 넷 실행 정책 (Net Execution Policy)

“이 스킬을 누구 컴퓨터에서 제일 먼저 실행할 것인가?” (반응 속도 결정)

멀티플레이 게임에서 핑(Ping)이 높아도 캐릭터가 즉각적으로 움직이게 하려면 이 설정이 필수적입니다.

  • Local Predicted (로컬 예측) 🌟: 유저가 버튼을 누르면 서버 허락을 기다리지 않고 내 화면에서 즉시(0.1초 만에) 스킬을 실행합니다. 이후 서버가 검증하여 정상이면 유지, 핵/오류면 강제로 롤백(Rollback)시킵니다. 즉각적인 반응이 필요한 거의 모든 플레이어 스킬에 사용합니다. (GAS의 꽃)
  • Local Only (로컬 전용): 내 컴퓨터(클라이언트)에서만 실행하고 서버에는 알리지 않습니다. 순수 시각적 연출이나 내 화면에만 보이는 UI/튜토리얼 스킬에 사용합니다.
  • Server Initiated (서버 주도): 서버가 명령을 내려야만 클라이언트 화면에서 스킬이 나갑니다. AI(몬스터)의 스킬이나 특정 지역 진입 시 서버가 강제로 발동시키는 함정/디버프에 사용합니다.
  • Server Only (서버 전용): 유저의 컴퓨터에서는 렌더링되지 않고 서버 내부에서만 조용히 실행됩니다. 체력 회복, 레벨업 스탯 계산 등 시각 효과 없이 데이터만 바꾸는 연산 스킬에 사용하여 클라이언트 부담을 줄입니다.

2. 넷 보안 정책 (Net Security Policy)

“이 스킬을 실행해달라고 ‘요청’할 수 있는 권한이 누구에게 있는가?” (해킹 방지)

클라이언트가 메모리를 변조해 스킬을 남발하는 것을 막기 위한 보안 설정입니다.

  • Client Or Server (기본값): 클라이언트가 버튼을 눌러 요청할 수도 있고, 서버가 강제로 실행시킬 수도 있습니다. 플레이어가 직접 조작하는 일반적인 전투 스킬에 사용합니다. (주로 Local Predicted와 짝꿍으로 쓰임)
  • Server Only Execution (서버만 실행 가능): 유저가 변조된 실행 신호를 보내도 서버가 철저히 무시합니다. 부활 스킬, 보상 지급, 즉사기 등 유저가 임의로 발동시키면 안 되는 치명적인 스킬에 걸어둡니다.
  • Server Only Termination (서버만 종료 가능): 스킬 시작은 유저가 할 수 있지만, 끄는 것은 오직 서버만 할 수 있습니다. 후딜레이 캔슬 핵을 막을 때 유용합니다.
  • Server Only: 실행과 종료 모두 서버만 건드릴 수 있는 가장 강력한 통제 상태입니다.



[UE5 GAS] C++와 블루프린트의 역할 분담 및 핵심 함수

Gameplay Ability System(GAS)을 사용할 때 모든 것을 C++로 짜거나 반대로 모든 것을 블루프린트로 짜는 것은 비효율적입니다. 가장 이상적인 구조는 “복잡한 로직은 C++가, 시각적 요소와 데이터 세팅은 블루프린트(BP)가” 담당하는 형태입니다.


1. C++와 블루프린트의 완벽한 역할 분담 (Best Practice)

보통 C++로 어빌리티의 부모 클래스(UGameplayAbility를 상속받은 커스텀 클래스)를 만들고, 이를 블루프린트로 상속받아 자식 클래스를 만들어 사용합니다.

구분C++에서 구현해야 할 것 (Logic & Core)블루프린트에서 세팅해야 할 것 (Data & Assets)
주요 역할복잡한 수학적 연산 및 코어 로직 제어시각적 피드백, 애니메이션, 태그 설정
개발 요소새로운 커스텀 Ability Task 만들기에디터 디테일 패널의 Ability Tags 설정
타겟팅트레이스(Raycast) 등 복잡한 타겟 찾기 수학 연산발동 시 재생할 몽타주(Montage) 에셋 연결
이펙트데미지 계산식(Execution Calculation) 구현어빌리티 성공 시 적용할 Gameplay Effect 지정
장점퍼포먼스(최적화)가 뛰어나고 디버깅이 명확함기획자나 아티스트가 코딩 없이 수치를 바로바로 수정 가능

팁: C++ 부모 클래스에서 UPROPERTY(EditDefaultsOnly)로 변수를 열어두면, 자식 블루프린트에서 애니메이션이나 이펙트 에셋을 쏙쏙 집어넣는 ‘데이터 껍데기’ 용도로 활용하기 아주 좋습니다.


2. ActivateAbility의 4가지 핵심 매개변수

어빌리티가 실행될 때 가장 먼저 호출되는 함수입니다. 이 4개의 변수에는 어빌리티를 실행하는 데 필요한 모든 ‘문맥(Context)’이 담겨 있습니다.

1
Super::ActivateAbility(Handle, ActorInfo, ActivationInfo, TriggerEventData);
  • Handle (FGameplayAbilitySpecHandle): 이 어빌리티 객체의 고유 식별자(ID)입니다. 멀티플레이어 환경에서 “이 서버의 이 캐릭터가 쓴 바로 그 스킬”을 추적할 때 사용하는 영수증 번호 같은 개념입니다.

  • ActorInfo (const FGameplayAbilityActorInfo*): 가장 많이 쓰는 꿀단지 변수입니다. 이 스킬을 시전한 캐릭터의 모든 정보가 들어있습니다. 시전자(Avatar), 주인(Owner), 플레이어 컨트롤러, 무브먼트 컴포넌트 등을 쉽게 가져올 수 있는 포인터들을 제공합니다.

  • ActivationInfo (const FGameplayAbilityActivationInfo): 이 스킬이 어떤 방식으로 실행되었는지에 대한 네트워크 정보가 담겨 있습니다. (예: 서버에서 주도적으로 켰는지, 클라이언트가 예측(Predicted)해서 켰는지 등)

  • TriggerEventData (const FGameplayEventData*): 만약 이 스킬이 직접 키보드를 눌러서 켠 게 아니라, ‘Gameplay Event’에 의해 촉발된 경우, 그 이벤트가 넘겨준 추가적인 데이터(누구를 맞췄는지, 데미지는 몇인지 등)가 담겨 있는 택배 상자입니다.


EndAbility의 매개변수와 의미

어빌리티가 끝날 때 반드시 호출해야 하는 함수입니다. 이걸 안 부르면 캐릭터가 스킬 상태에 영원히 갇히게 됩니다.

1
EndAbility(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, true, false);

앞의 3개 변수는 ActivateAbility에서 받은 것을 그대로 넘겨주면 됩니다. 뒤의 두 개 bool 값이 중요합니다.

  • 4번째 인자 bReplicateEndAbility (기본값 보통 true): 이 스킬이 끝났다는 사실을 네트워크를 통해 서버/클라이언트에 알릴 것인가? 입니다. 당연히 대부분 true로 설정하여 동기화를 맞춰야 합니다.

  • 5번째 인자 bWasCancelled (자연 종료 false / 강제 취소 true): 이 스킬이 할 일을 다 하고 자연스럽게 끝났다면 false를 줍니다. 기절을 당했거나, 다른 스킬에 의해 강제로 캔슬 당해서 끊겼다면 true를 줍니다. 이에 따라 로직 내부에서 뒷정리 방식이 달라질 수 있습니다.


4. Ability Task 사용법과 헤더(Header) 포함의 이유

GAS에서 시간이 걸리는 작업(애니메이션 재생, 목표 지점 이동 등)은 항상 Ability Task라는 비동기 노드를 생성해서 처리합니다.

1
2
3
4
5
6
7
8
9
10
11
12
// 1. Task 생성 (어빌리티 내부에서)
UAbilityTask_MoveToLocation* MoveToLocation = UAbilityTask_MoveToLocation::MoveToLocation(
    this, NAME_None, TargetLocation, MoveDuration, nullptr, nullptr);

if (MoveToLocation)
{
    // 2. 목적지에 도착했을 때(OnTargetLocationReached) 실행될 내 함수(&UGA_Flash::OnMoveFinished)를 연결(Bind)
    MoveToLocation->OnTargetLocationReached.AddDynamic(this, &UGA_Flash::OnMoveFinished);
    
    // 3.  세팅이 다 끝났으니, 이제 실제로 작동 시작!
    MoveToLocation->ReadyForActivation();
}

왜 헤더 파일을 일일이 추가해야 할까? 언리얼 엔진은 컴파일 속도를 높이기 위해, 내가 쓰지도 않을 거대한 코드 덩어리들을 미리 다 불러오지 않습니다. (이를 전방 선언, Forward Declaration의 원리라고 합니다.)

  • C++ 파일(.cpp)에서 UAbilityTask_MoveToLocation라는 녀석을 생성하고 그 내부의 델리게이트(OnTargetLocationReached)에 접근하려면, 컴파일러에게 “이 클래스가 정확히 어떻게 생겨먹었는지 설계도를 보여줘!”라고 알려야 합니다.
  • 그 설계도가 바로 #include "Abilities/Tasks/AbilityTask_MoveToLocation.h" 입니다.
  • 만약 몽타주를 재생하는 태스크를 쓰고 싶다면 #include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"를 추가로 적어줘야 합니다. 쓸 도구의 설명서(Header)를 매번 꺼내오는 과정이라고 이해하시면 됩니다!
This post is licensed under CC BY 4.0 by the author.