67 KiB
DS-전투시스템 종합분석
문서 개요
본 문서는 언리얼 엔진 에셋(DataTable, AnimMontage, Blueprint, CurveTable)을 JSON으로 익스포트하여 분석한 전투 로직 시스템에 대한 기술 문서입니다.
분석 대상 스토커: Hilda, Urud, Nave, Baran, Rio, Clad, Rene, Sinobu, Lian, Cazimord (10명)
작성 일자: 2025-10-23
익스포트 데이터: DS-전투밸런스_분석자료/20251023_114317/
목차
- 개요 및 Asset Export 시스템
- DataTable 구조
- AnimMontage 타이밍 시스템
- Blueprint Ability 및 캔슬 시스템
- GameplayEffect 메커니즘
- DT_Skill 특수 케이스
- 코드-어셋 통합 흐름
- JSON 사용 가이드
1. 개요 및 Asset Export 시스템
1.1 Asset Export to JSON 기능
언리얼 엔진 에셋은 기본적으로 바이너리 형식으로 저장되어 LLM이나 외부 분석 도구가 직접 접근할 수 없습니다. 이를 해결하기 위해 Asset Export to JSON 에디터 확장 기능을 개발하였습니다.
참고 문서: DS-전투밸런스_분석자료/DS-Asset_Export_to_JSON.md
주요 기능
- 지원 에셋 타입: DataTable, Blueprint, AnimMontage, CurveTable
- 프로젝트 설정 통합:
편집 → 프로젝트 설정 → 플러그인 → Asset Export to JSON - 타임스탬프 익스포트: 익스포트 히스토리 보관을 위한 타임스탬프 폴더 생성
- 완전한 데이터 추출:
- DataTable: 모든 행/열 데이터
- Blueprint: 변수, 함수, 컴포넌트, 이벤트 그래프 노드 구조
- AnimMontage: 섹션, 노티파이, 커스텀 프로퍼티, 슬롯 애니메이션
- CurveTable: RichCurves 및 SimpleCurves 키 데이터
익스포트 실행
툴 → WorldStalker → Export Assets to JSON
출력 위치
Content/Exports/20251023_114317/
├── DataTable.json (1,151 에셋)
├── Blueprint.json (1,151 에셋)
├── AnimMontage.json (809 에셋)
└── CurveTable.json (8 에셋)
1.2 전투 로직 분석 범위
본 문서에서는 익스포트된 JSON 데이터를 기반으로 다음 전투 시스템을 분석합니다:
스토커별 전투 데이터
| 스토커 | 클래스 | 주요 특징 |
|---|---|---|
| Hilda | 전사 | Counter 스킬, 방패 방어 |
| Urud | 원거리 | Reload 시스템, 궁극기 'Explosion' 범위 피해 |
| Nave | 마법사 | 캐스팅 스킬, 궁극기 'Liberation' (DT_Skill 피해) |
| Baran | 전사 | 중무장 탱커, Pulling 체인 메커니즘 |
| Rio | 암살자 | Chain Score 시스템 (최대 3 스택) |
| Clad | 성직자 | 힐링 및 언데드 특효 |
| Rene | 소환사 | Spirit 소환, Lifesteal 효과 |
| Sinobu | 닌자 | Shuriken 충전 시스템, 'Swap' 인술 (텔레포트) |
| Lian | 레인저 | Reload 시스템, Precision Aim (조준 시스템) |
| Cazimord | 전사 | Flash 스킬 스택, Parrying 시스템 |
분석 계층
스토커 전투 시스템
│
├── DataTable Layer (밸런스 데이터)
│ ├── DT_CharacterStat (기본 스탯, 스킬 목록)
│ ├── DT_Skill (스킬 데이터, 피해 배율, 쿨타임)
│ └── DT_CharacterAbility (기본 공격 어빌리티 매핑)
│
├── AnimMontage Layer (타이밍 데이터)
│ ├── 기본 공격 몽타주 (AM_PC_[Stalker]_B_Attack_*)
│ ├── 스킬 몽타주 (스킬별 애니메이션)
│ └── 노티파이 시스템
│ ├── ANS_AttackState_C (공격 상태, 피해 배율)
│ ├── AnimNotifyState_AttackWithEquip (히트 판정 타이밍)
│ ├── ANS_SkillCancel_C (스킬 캔슬 윈도우)
│ └── AN_SetAutoTarget_C (자동 타게팅)
│
├── Blueprint Ability Layer (로직 구현)
│ ├── GA_Attack (기본 공격)
│ ├── GA_Skill_* (스토커별 스킬 구현)
│ ├── Activation Order Group (우선순위 캔슬 시스템)
│ └── 특수 시스템 (Reload, Chain Score, Parrying 등)
│
└── GameplayEffect Layer (효과 적용)
├── GE_Attack_* (피해 효과)
├── GE_Skill_* (스킬 효과)
└── GE_Buff/Debuff_* (버프/디버프)
1.3 JSON 참조 규칙
중요: JSON 파일은 에디터에서 익스포트한 결과물로, 소스 코드처럼 고정된 라인 번호가 없습니다.
올바른 참조 방법
✅ Asset 이름으로 참조
DT_CharacterStat 어셋의 "hilda" 행
AM_PC_Hilda_B_Skill_SwordStrike 몽타주
GA_Skill_Hilda_SwordStrike_C 블루프린트
❌ 라인 번호로 참조하지 않음
DataTable.json:358143-358192 (X)
JSON 구조 예시
DataTable.json:
{
"AssetName": "DT_CharacterStat",
"RowStructure": "CharacterStatData",
"Rows": [
{
"RowName": "hilda",
"Data": {
"name": "힐다",
"defaultSkills": ["SK100201", "SK100202", "SK100204"],
"subSkill": "SK100101",
"ultimateSkill": "SK100301"
}
}
]
}
AnimMontage.json:
{
"AssetName": "AM_PC_Hilda_B_Skill_SwordStrike",
"SequenceLength": 1.8,
"AnimNotifies": [
{
"NotifyStateClass": "ANS_SkillCancel_C",
"TriggerTime": 1.3,
"Duration": 0.5
}
]
}
2. DataTable 구조
2.1 DT_CharacterStat (스토커 기본 스탯 및 스킬 매핑)
DT_CharacterStat은 각 스토커의 기본 스탯과 사용 가능한 스킬 목록을 정의합니다.
구조
| 필드 | 타입 | 설명 |
|---|---|---|
name |
String | 스토커 이름 (한글) |
jobName |
String | 직업 (전사, 원거리, 마법사 등) |
str |
Int | 힘 (물리 공격력 영향) |
dex |
Int | 민첩 (공격 속도, 크리티컬 영향) |
int |
Int | 지능 (마법 공격력 영향) |
con |
Int | 체력 (HP, 방어력 영향) |
wis |
Int | 지혜 (마나, 마법 방어력 영향) |
hP |
Float | 기본 HP |
mP |
Float | 기본 MP |
manaRegen |
Float | 마나 재생 속도 |
defaultSkills |
Array | 기본 스킬 ID 목록 (3-4개) |
subSkill |
String | 서브 스킬 ID (특수 스킬, 쿨타임 0초) |
ultimateSkill |
String | 궁극기 스킬 ID |
스토커별 스탯 분포
전체 스탯 합계: 75 포인트 (모든 스토커 동일)
힘 중심 스토커 (STR 20+)
Hilda (전사):
STR: 20, DEX: 15, INT: 10, CON: 20, WIS: 10
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK100201 (Sword Strike), SK100202 (Counter), SK100204 (Provoke)
Sub: SK100101 (Blocking)
Ultimate: SK100301 (Blood Moon)
Baran (전사):
STR: 25, DEX: 10, INT: 5, CON: 25, WIS: 10
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK130204 (Pulling), SK130203 (Smash), SK130206 (Sword Stab)
Sub: SK130101 (Blocking)
Ultimate: SK130301 (Rock Breaker)
민첩 중심 스토커 (DEX 20+)
Urud (원거리):
STR: 15, DEX: 20, INT: 10, CON: 15, WIS: 15
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK110205 (Multi Shot), SK110204 (Poison Arrow), SK110201 (Make Trap), SK110207 (Reload)
Sub: SK110101 (Arrow Attack)
Ultimate: SK110301 (Explosion)
Rio (암살자):
STR: 15, DEX: 25, INT: 10, CON: 15, WIS: 10
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK140201 (Rapid Stab), SK140205 (Approach), SK140202 (Throwing Dagger)
Sub: SK140101 (Dropping Attack)
Ultimate: SK140301 (Sensitive)
Sinobu (닌자):
STR: 10, DEX: 25, INT: 10, CON: 15, WIS: 15
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK180202 (Bomb Talisman), SK180203 (Thunder Kick), SK180205 (Ninpo Change)
Sub: SK180101 (Shuriken)
Ultimate: SK180301 (Deflect)
Cazimord (전사):
STR: 15, DEX: 25, INT: 10, CON: 15, WIS: 10
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK170201 (Flash), SK170202 (Blade Storm), SK170203 (Burn)
Sub: SK170101 (Parrying)
Ultimate: SK170301 (Mana Stone Burn)
Lian (레인저):
STR: 10, DEX: 20, INT: 10, CON: 15, WIS: 20
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK190207 (Rapid Shot), SK190205 (Back Step), SK190201 (Dark Souls), SK190209 (Reload)
Sub: SK190101 (Charging Bow)
Ultimate: SK190301 (Manastone Silence)
지능 중심 스토커 (INT 20+)
Nave (마법사):
STR: 10, DEX: 10, INT: 25, CON: 10, WIS: 20
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK120201 (Magic Missile), SK120202 (Fire Wall), SK120206 (Wind Force)
Sub: SK120101 (Mana Restore)
Ultimate: SK120301 (Escape 4)
Rene (소환사):
STR: 10, DEX: 10, INT: 20, CON: 10, WIS: 25
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK160202 (Summon Ifrit), SK160206 (Summon Shiva), SK160203 (Poison Gas)
Sub: SK160101 (Scratching)
Ultimate: SK160301 (Mana Stone Carnival)
균형 스토커
Clad (성직자):
STR: 15, DEX: 10, INT: 10, CON: 20, WIS: 20
HP: 100, MP: 50, Mana Regen: 0.2
Skills: SK150206 (Holy Cure), SK150201 (Turn Undead), SK150202 (Holy Light)
Sub: SK150101 (Block)
Ultimate: SK150301 (Gold)
2.2 DT_Skill (스킬 상세 데이터)
DT_Skill은 각 스킬의 피해 배율, 쿨타임, 원소 타입, 사용 몽타주, 연결된 Ability 클래스 등을 정의합니다.
구조
| 필드 | 타입 | 설명 |
|---|---|---|
RowName |
String | 스킬 ID (SK + 6자리 숫자) |
stalkerName |
String | 소유 스토커 이름 (소문자) |
bIsUltimate |
Bool | 궁극기 여부 |
skillName |
String | 스킬 이름 |
skillDamageRate |
Float | 기본 피해 배율 (1.0 = 100%) |
skillManaCost |
Float | 마나 소모량 |
coolTime |
Float | 쿨타임 (초) |
skillAttackType |
Enum | 공격 타입 (PhysicalSkill, MagicalSkill, Normal) |
skillElementType |
Enum | 원소 타입 (None, Fire, Lightning, Poison, Water, Holy, Dark) |
useMontages |
Array | 사용할 몽타주 경로 목록 |
abilityClass |
String | 연결된 GA_* 블루프린트 경로 |
gameplayEffectSet |
Array | 적용할 GameplayEffect 목록 |
스킬 타입 분류
PhysicalSkill (물리 스킬)
- 힘(STR) 또는 민첩(DEX) 스탯의 영향을 받음
- 방어력(Defense)에 의해 감소
- 예시: Hilda의 Sword Strike, Rio의 Rapid Stab, Cazimord의 Flash
MagicalSkill (마법 스킬)
- 지능(INT) 또는 지혜(WIS) 스탯의 영향을 받음
- 마법 저항력(MagicalResistancePer)에 의해 감소
- 원소 타입에 따라 추가 저항력 적용 (Fire, Lightning, Poison 등)
- 예시: Nave의 Magic Missile, Rene의 Summon Ifrit, Clad의 Turn Undead
Normal (일반/유틸리티)
- 피해를 주지 않거나 특수 메커니즘을 가진 스킬
- 스탯 배율 없이 고정 효과 또는 0 피해
- 예시: Hilda의 Blocking, Urud의 Reload, Rio의 Approach
원소 타입별 특성
| 원소 | 저항 스탯 | 주요 사용 스토커 |
|---|---|---|
| None | - | 대부분 (범용 스킬) |
| Lightning | lightningResistancePer | Hilda (Sword Strike), Sinobu (Thunder Kick) |
| Fire | fireResistancePer | Nave (Fire Wall) |
| Poison | poisonResistancePer | Urud (Poison Arrow), Rene (Poison Gas) |
| Water | waterResistancePer | - |
| Holy | holyResistancePer | Clad (Turn Undead), Lian (Dark Souls) |
| Dark | darkResistancePer | Rene (Poison Gas - Dark 속성도 보유) |
스킬 예시
Hilda - SK100201 (Sword Strike):
{
"RowName": "SK100201",
"stalkerName": "hilda",
"skillName": "Sword Strike",
"skillDamageRate": 1.3,
"coolTime": 6.0,
"skillAttackType": "PhysicalSkill",
"skillElementType": "Lightning",
"useMontages": [
"/Game/_Art/_Character/PC/Hilda/AnimMontage/Skill/AM_PC_Hilda_B_Skill_Ready.AM_PC_Hilda_B_Skill_Ready",
"/Game/_Art/_Character/PC/Hilda/AnimMontage/Skill/AM_PC_Hilda_B_Skill_SwordStrike.AM_PC_Hilda_B_Skill_SwordStrike"
],
"abilityClass": "/Game/Blueprints/Characters/Hilda/GA_Skill_Hilda_SwordStrike.GA_Skill_Hilda_SwordStrike_C"
}
Nave - SK120301 (Escape 4 / Liberation 궁극기):
{
"RowName": "SK120301",
"stalkerName": "nave",
"bIsUltimate": true,
"skillName": "Escape 4",
"skillDamageRate": 1.0,
"coolTime": 0.0,
"skillAttackType": "MagicalSkill",
"skillElementType": "None",
"useMontages": [
"/Game/_Art/_Character/PC/Nave/AnimMontage/Ultimate/AM_PC_Nave_B_Skill_Escape4.AM_PC_Nave_B_Skill_Escape4"
],
"abilityClass": "/Game/Blueprints/Characters/Nave/GA_Skill_Nave_Escape4.GA_Skill_Nave_Escape4_C"
}
특수 사항: Nave의 궁극기는 AnimMontage의 노티파이가 아닌 DT_Skill의 skillDamageRate와 gameplayEffectSet에서 직접 피해를 정의합니다. (Section 6 참조)
Urud - SK110301 (Explosion 궁극기):
{
"RowName": "SK110301",
"stalkerName": "urud",
"bIsUltimate": true,
"skillName": "Explosion",
"skillDamageRate": 1.0,
"coolTime": 0.0,
"skillAttackType": "Normal",
"skillElementType": "None",
"useMontages": [
"/Game/_Art/_Character/PC/Urud/AnimMontage/Ultimate/AM_PC_Urud_B_Skill_Explosion.AM_PC_Urud_B_Skill_Explosion",
"/Game/_Art/_Character/PC/Urud/AnimMontage/Base/AM_PC_Urud_B_Skill_Equipment.AM_PC_Urud_B_Skill_Equipment"
],
"abilityClass": "/Game/Blueprints/Abilities/GA_Skill_Casting_Ultimate.GA_Skill_Casting_Ultimate_C"
}
특수 사항: Urud의 궁극기 'Explosion'은 투척한 돌이 적중 시 범위 피해를 줍니다. 피해는 AnimMontage의 노티파이 또는 GA_Skill Blueprint에서 처리됩니다.
2.3 DT_CharacterAbility (기본 공격 어빌리티 매핑)
DT_CharacterAbility는 각 스토커의 기본 공격(좌클릭)에 사용되는 Ability 클래스를 매핑합니다.
구조
| 필드 | 타입 | 설명 |
|---|---|---|
characterName |
String | 스토커 이름 |
abilityClass |
String | 기본 공격 Ability 경로 |
대부분의 스토커는 공통 GA_Attack 클래스를 사용하지만, 일부 스토커는 커스텀 공격 로직을 가집니다.
공통 기본 공격
GA_Attack 사용 스토커:
- Hilda, Baran, Rio, Clad, Rene, Nave, Sinobu, Cazimord
기본 공격 로직:
- 장착한 무기의
montages배열에서 몽타주 선택 - 콤보 시스템: 연속 입력 시 다음 몽타주로 체인
- AnimNotifyState_AttackWithEquip 노티파이에서 히트 판정
- ANS_AttackState_C 노티파이에서 피해 배율 적용
특수 기본 공격
Urud, Lian (원거리 스토커):
- Ability:
GA_Attack_Firearm(총기형 무기 전용) - 특징:
- 탄약 시스템 (GameplayTag 기반 탄약 카운트)
- 탄약 소진 시 자동으로 Reload 스킬 트리거
- 조준 중 이동 속도 감소
- Reload 스킬(SK110207, SK190209)로 재장전
2.4 스토커별 스킬 매핑 요약
| 스토커 | 기본 스킬 (3-4개) | 서브 스킬 (쿨타임 0) | 궁극기 | 특수 시스템 |
|---|---|---|---|---|
| Hilda | Sword Strike, Counter, Provoke | Blocking | Blood Moon | Counter 반격, 방패 방어 |
| Urud | Multi Shot, Poison Arrow, Make Trap, Reload | Arrow Attack | Explosion | Reload 시스템, 범위 피해 궁극기 |
| Nave | Magic Missile, Fire Wall, Wind Force | Mana Restore | Escape 4 | 캐스팅 스킬, Liberation 피해(DT_Skill) |
| Baran | Pulling, Smash, Sword Stab | Blocking | Rock Breaker | Pulling 체인, 중력 조작 |
| Rio | Rapid Stab, Approach, Throwing Dagger | Dropping Attack | Sensitive | Chain Score (3 스택) |
| Clad | Holy Cure, Turn Undead, Holy Light | Block | Gold | 힐링, 언데드 특효 |
| Rene | Summon Ifrit, Summon Shiva, Poison Gas | Scratching | Mana Stone Carnival | Spirit 소환, Lifesteal |
| Sinobu | Bomb Talisman, Thunder Kick, Ninpo Change | Shuriken | Deflect | Shuriken 충전, Swap 인술 |
| Lian | Rapid Shot, Back Step, Dark Souls, Reload | Charging Bow | Manastone Silence | Reload 시스템, Precision Aim, 충전 3스택 |
| Cazimord | Flash, Blade Storm, Burn | Parrying | Mana Stone Burn | Flash 스택, Parrying 반격 |
3. AnimMontage 타이밍 시스템
3.1 AnimMontage 노티파이 시스템 개요
AnimMontage는 애니메이션 재생 중 특정 타이밍에 게임 로직을 트리거하는 노티파이(Notify) 시스템을 제공합니다. 전투 시스템에서는 노티파이를 통해 다음을 구현합니다:
- 공격 판정 타이밍: 무기가 적을 타격하는 정확한 프레임
- 피해 배율 조정: 공격 구간별 피해량 증감
- 스킬 캔슬 윈도우: 스킬을 중단하고 다음 행동으로 전환 가능한 시간대
- 자동 타게팅: 적을 자동으로 추적하는 시점
- 이동 제한: 스킬 사용 중 이동 속도 조절
- 벽 충돌 체크: 근거리 공격 시 벽에 막히는지 검사
노티파이 타입
| 타입 | 설명 | 예시 |
|---|---|---|
| Notify | 특정 시점에 한 번 실행 | AN_SetAutoTarget_C (자동 타게팅 활성화) |
| NotifyState | 시작~종료 구간 동안 지속 | ANS_AttackState_C (공격 상태 유지) |
3.2 주요 노티파이 클래스
ANS_AttackState_C (공격 상태 및 피해 배율)
타입: NotifyState (구간 지속)
역할:
- 공격 판정이 가능한 구간 정의
- 피해 배율 조정 (
AddNormalAttackPer프로퍼티)
프로퍼티:
| 프로퍼티 | 타입 | 설명 |
|---|---|---|
TriggerTime |
Float | 시작 시간 (초) |
Duration |
Float | 지속 시간 (초) |
AddNormalAttackPer |
Float | 피해 배율 증감 (%) |
예시 - Baran 기본 공격 1타:
{
"NotifyStateClass": "ANS_AttackState_C",
"TriggerTime": 0.0,
"Duration": 1.17,
"CustomProperties": {
"AddNormalAttackPer": "30.0"
}
}
→ 0.0초부터 1.17초까지 공격 상태이며, 피해량이 +30% 증가
AnimNotifyState_AttackWithEquip (히트 판정 타이밍)
타입: NotifyState (구간 지속)
역할:
- 무기의 궤적을 따라 히트 판정 수행
- 다중 히트 지점 정의 (TimeArray, LocationArray, RotationArray)
- 공격 타입 태그 지정 (Event.Attack.Normal, Event.Attack.Skill 등)
프로퍼티:
| 프로퍼티 | 타입 | 설명 |
|---|---|---|
TriggerTime |
Float | 시작 시간 (초) |
Duration |
Float | 지속 시간 (초) |
AttackTag |
GameplayTag | 공격 타입 태그 |
TimeArray |
Array | 다중 히트 시간 배열 |
LocationArray |
Array | 히트 위치 배열 |
RotationArray |
Array | 히트 방향 배열 |
예시 - Baran 기본 공격 1타 히트 판정:
{
"NotifyStateClass": "AnimNotifyState_AttackWithEquip",
"TriggerTime": 0.8,
"Duration": 0.12,
"CustomProperties": {
"AttackTag": "(TagName=\"Event.Attack.Normal\")",
"TimeArray": ["0.0", "0.033333", "0.066667", "0.1"],
"LocationArray": ["(X=0,Y=0,Z=0)", "(X=20,Y=10,Z=5)", ...]
}
}
→ 0.8초부터 0.92초까지 4개의 히트 포인트에서 판정 (0.033초 간격)
ANS_SkillCancel_C (스킬 캔슬 윈도우)
타입: NotifyState (구간 지속)
역할:
- 스킬의 자연스러운 종료 타이밍 정의
- 이 구간에서 같거나 낮은 Activation Order Group 스킬로 캔슬 가능
- DPS 최적화에 중요한 역할
프로퍼티:
| 프로퍼티 | 타입 | 설명 |
|---|---|---|
TriggerTime |
Float | 캔슬 윈도우 시작 시간 (초) |
Duration |
Float | 캔슬 윈도우 지속 시간 (초) |
예시 - Hilda Sword Strike 스킬:
{
"NotifyStateClass": "ANS_SkillCancel_C",
"TriggerTime": 1.3,
"Duration": 0.5
}
→ 1.3초부터 1.8초까지 캔슬 가능 (스킬 종료 구간)
중요: ANS_SkillCancel_C는 Activation Order Group 시스템과 독립적으로 작동합니다 (OR 조건). 자세한 내용은 Section 4.2 참조.
AN_SetAutoTarget_C (자동 타게팅)
타입: Notify (순간 실행)
역할:
- 특정 시점에 가장 가까운 적을 자동으로 타게팅
- 캐릭터 회전 및 카메라 방향 조정
예시:
{
"NotifyClass": "AN_SetAutoTarget_C",
"TriggerTime": 0.1
}
→ 0.1초 시점에 자동 타게팅 활성화
ANS_WeaponWallCheck_C (벽 충돌 검사)
타입: NotifyState (구간 지속)
역할:
- 근거리 무기 공격 시 벽과의 충돌 검사
- 벽에 막히면 공격 판정 무효화
ANS_DisableBlockingState_C (방어 불가 구간)
타입: NotifyState (구간 지속)
역할:
- 특정 구간에서 방어(Blocking) 불가 상태로 만듦
- 공격 모션 중 방어 전환 방지
3.3 스토커별 기본 공격 타이밍 분석
기본 공격은 좌클릭으로 실행되며, 대부분 3타 콤보로 구성됩니다. 각 타의 AnimMontage에서 피해 배율과 히트 판정 타이밍을 추출했습니다.
3타 콤보 총 소요 시간 (공격 속도 랭킹)
| 순위 | 스토커 | 1타 | 2타 | 3타 | 합계 | 특징 |
|---|---|---|---|---|---|---|
| 1 | Rio | 1.200s | 1.300s | 1.367s | 3.867s | 최고속 암살자 |
| 2 | Sinobu | 1.367s | 1.333s | 1.334s | 4.034s | 빠른 공격 |
| 3 | Hilda | 1.500s | 1.500s | 1.567s | 4.567s | 중간 속도 |
| 4 | Nave | 1.733s | 1.667s | 1.767s | 5.167s | 캐스터 타입 |
| 5 | Cazimord | 1.667s | 1.900s | 1.867s | 5.434s | 듀얼 소드 |
| 6 | Baran | 1.900s | 1.700s | 1.966s | 5.566s | 무거운 공격 |
| 7 | Rene | 2.000s | 1.900s | 2.000s | 5.900s | 느린 소환사 |
| 8 | Clad | 2.000s | 2.000s | 2.000s | 6.000s | 가장 느림 |
참고:
- Urud, Lian: 원거리 총기형 공격 (발사 속도는 별도, Reload 필요)
기본 공격 피해 배율 (AddNormalAttackPer)
| 스토커 | 1타 | 2타 | 3타 | 특징 |
|---|---|---|---|---|
| Baran | +30% | +35% | +30% | 가장 높은 피해 (탱커 타입) |
| Clad | +30% | +50% | +30% | 2타 강화 (성직자 평타) |
| Hilda | +30% | +30% | +30% | 일정한 피해 |
| Cazimord | -5% | +15% | +20% | 3타 강화 (듀얼 소드) |
| Sinobu | -30% | +10% | -30% | 속도 우선, 낮은 피해 |
| Rio | -30% | -20% | -15% | 낮은 피해 (속도로 보완) |
| Nave | 0% | 0% | 0% | 배율 없음 (마법 공격) |
| Rene | 0% | 0% | 0% | 배율 없음 (소환수 의존) |
해석:
- Baran, Clad: 느리지만 강력한 공격 (STR/CON 스토커)
- Rio, Sinobu: 빠르지만 약한 공격 (DEX 스토커, 스킬 의존)
- Nave, Rene: INT/WIS 스토커로 평타보다 스킬 중심
기본 공격 몽타주 예시
Hilda - AM_PC_Hilda_B_Attack_W01_01 (1타):
Duration: 1.5초
ANS_AttackState_C: 0.0~1.133초, AddNormalAttackPer: +30%
AnimNotifyState_AttackWithEquip: 0.733~0.867초 (히트 판정)
AN_SetAutoTarget_C: 0.1초 (자동 타게팅)
Rio - AM_PC_Rio_B_Attack_W01_01 (1타):
Duration: 1.2초
ANS_AttackState_C: 0.0~0.9초, AddNormalAttackPer: -30%
AnimNotifyState_AttackWithEquip: 0.4~0.533초 (빠른 히트)
Baran - AM_PC_Baran_B_Attack_W01_01 (1타):
Duration: 1.9초
ANS_AttackState_C: 0.0~1.17초, AddNormalAttackPer: +30%
AnimNotifyState_AttackWithEquip: 0.8~0.92초 (느린 히트)
Cazimord - AM_PC_Cazimord_B_Attack_W01_01 (1타):
Duration: 1.667초
ANS_AttackState_C: 0.0~0.900초, AddNormalAttackPer: -5%
AnimNotifyState_AttackWithEquip: 0.592~0.733초, 0.710~0.891초 (듀얼 소드 더블 히트)
3.4 스토커별 스킬 타이밍 분석
각 스토커의 주요 스킬 몽타주에서 타이밍 데이터를 추출했습니다.
Hilda (전사)
SK100201 - Sword Strike (AM_PC_Hilda_B_Skill_SwordStrike):
Duration: 1.8초
ANS_SkillCancel_C: 1.3~1.8초 (캔슬 윈도우 0.5초)
ANS_AttackState_C: 0.0~1.533초, AddNormalAttackPer: +100%
AnimNotifyState_AttackWithEquip: 0.6~0.8초
SK100202 - Counter (AM_PC_Hilda_B_Skill_Counter):
Duration: 2.567초
ANS_SkillCancel_C: 없음 (캔슬 불가)
특수: 반격 판정 노티파이 포함
SK100204 - Provoke (AM_PC_Hilda_B_Skill_Provoke):
Duration: 3.0초
ANS_SkillCancel_C: 없음
특수: 도발 범위 설정 노티파이
Urud (원거리)
SK110205 - Multi Shot (AM_PC_Urud_B_Skill_MultiArrow):
Duration: 2.0초
ANS_SkillCancel_C: 없음
AnimNotifyState_AttackWithEquip: 다중 화살 발사 타이밍
SK110204 - Poison Arrow (AM_PC_Urud_B_Skill_PoisonArrow):
Duration: 1.8초
ANS_SkillCancel_C: 없음
특수: Poison 상태 이상 적용
SK110207 - Reload (AM_PC_Urud_B_Skill_Reload):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: 재장전 완료 노티파이 (탄약 충전)
Nave (마법사)
SK120201 - Magic Missile (AM_PC_Nave_B_Skill_MagicMissile):
Duration: 1.5초
ANS_SkillCancel_C: 없음
특수: 캐스팅 타입 (CanMove_CanRelease)
SK120202 - Fire Wall (AM_PC_Nave_B_Skill_FireWall):
Duration: 1.8초
ANS_SkillCancel_C: 없음
특수: 범위 화염 장판 생성
SK120301 - Escape 4 (Liberation 궁극기) (AM_PC_Nave_B_Skill_Escape4):
Duration: 3.5초
ANS_SkillCancel_C: 없음
특수: DT_Skill에서 피해 정의 (AnimMontage 노티파이 없음)
Baran (전사)
SK130204 - Pulling (AM_PC_Baran_B_Skill_Pulling):
Duration: 1.7초
ANS_SkillCancel_C: 1.276~1.700초 (캔슬 윈도우 0.424초)
특수: Pulling 체인 판정 (적 끌어당김)
SK130203 - Smash (AM_PC_Baran_B_Skill_Smash):
Duration: 2.0초
ANS_SkillCancel_C: 없음
AnimNotifyState_AttackWithEquip: 1.0~1.2초 (강타 판정)
SK130206 - Sword Stab (AM_PC_Baran_B_Skill_SwordStab):
Duration: 1.733초
ANS_SkillCancel_C: 1.660~1.733초 (캔슬 윈도우 0.073초, 매우 짧음)
AnimNotifyState_AttackWithEquip: 0.8~1.0초
Rio (암살자)
SK140201 - Rapid Stab (AM_PC_Rio_B_Skill_RapidStab):
Duration: 1.833초
ANS_SkillCancel_C: 1.513~1.833초 (캔슬 윈도우 0.32초)
특수: 빠른 연속 찌르기 (다중 히트)
SK140205 - Approach (AM_PC_Rio_B_Skill_Approach):
Duration: 1.5초
ANS_SkillCancel_C: 없음
특수: 돌진 이동 스킬 (피해 없음)
SK140202 - Throwing Dagger (AM_PC_Rio_B_Skill_ThrowingDagger):
Duration: 1.2초
ANS_SkillCancel_C: 없음
특수: 원거리 투척 공격
Clad (성직자)
SK150206 - Holy Cure (AM_PC_Clad_B_Skill_HolyCure):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: 힐링 효과 (피해 없음)
SK150201 - Turn Undead (AM_PC_Clad_B_Skill_TurnUndead):
Duration: 2.5초
ANS_SkillCancel_C: 없음
특수: 언데드 특효 피해
SK150202 - Holy Light (AM_PC_Clad_B_Skill_HolyLight):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: 범위 버프 효과
Rene (소환사)
SK160202 - Summon Ifrit (AM_PC_Rene_B_Skill_SummonIfrit):
Duration: 2.5초
ANS_SkillCancel_C: 없음
특수: Ifrit 소환수 생성
SK160206 - Summon Shiva (AM_PC_Rene_B_Skill_SummonShiva):
Duration: 2.5초
ANS_SkillCancel_C: 없음
특수: Shiva 소환수 생성
SK160203 - Poison Gas (AM_PC_Rene_B_Skill_PoisonGas):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: 독 구름 장판 생성
Sinobu (닌자)
SK180202 - Bomb Talisman (AM_PC_Sinobu_B_Skill_BombTalisman):
Duration: 1.5초
ANS_SkillCancel_C: 없음
특수: 폭탄 부적 투척
SK180203 - Thunder Kick (AM_PC_Sinobu_B_Skill_ThunderKick):
Duration: 1.8초
ANS_SkillCancel_C: 없음
AnimNotifyState_AttackWithEquip: 0.6~0.8초
특수: 번개 속성 발차기
SK180205 - Ninpo Change (Swap) (AM_PC_Sinobu_B_Skill_NinpoChange):
Duration: 1.0초
ANS_SkillCancel_C: 없음
특수: 텔레포트 인술 (위치 교환)
Lian (레인저)
SK190207 - Rapid Shot (AM_PC_Lian_B_Skill_RapidShot1):
Duration: 2.626초
ANS_SkillCancel_C: 2.333~2.626초 (캔슬 윈도우 0.293초)
특수: 연속 사격 (6발)
SK190205 - Back Step Bow Attack (AM_PC_Lian_B_Skill_BackStepBowAttack):
Duration: 1.701초
ANS_SkillCancel_C: 1.492~1.701초 (캔슬 윈도우 0.209초)
특수: 백스텝 + 사격 (회피 기능)
SK190201 - Dark Souls (AM_PC_Lian_B_Skill_DarkSouls_NoCasting):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: Holy 속성 관통 공격
SK190209 - Reload (AM_PC_Lian_B_Skill_Reload):
Duration: 2.0초
ANS_SkillCancel_C: 없음
특수: 재장전 (탄약 충전)
Cazimord (전사)
SK170201 - Flash (AM_PC_Cazimord_B_Skill_Flash, AM_PC_Cazimord_B_Skill_Flash_Active):
Flash (준비): Duration: 1.0초
Flash_Active (발동): Duration: 1.733초
ANS_SkillCancel_C: 1.001~1.733초 (Active 몽타주, 캔슬 윈도우 0.732초)
특수: Flash 스택 시스템 (최대 3스택)
SK170202 - Blade Storm (AM_PC_Cazimord_B_Skill_BladeStorm):
Duration: 3.0초
ANS_SkillCancel_C: 2.5~3.0초 (캔슬 윈도우 0.5초)
특수: 회전 범위 공격
SK170203 - Burn (AM_PC_Cazimord_B_Skill_Burn):
Duration: 2.5초
ANS_SkillCancel_C: 없음
특수: Fire 지속 피해
SK170101 - Parrying (서브 스킬) (AM_PC_Cazimord_B_Skill_Parrying):
Duration: 1.5초
ANS_SkillCancel_C: 없음
특수: 패링 성공 시 반격 + Flash 스택 충전
3.5 ANS_SkillCancel_C 보유 스킬 요약
전체 스킬 중 ANS_SkillCancel_C 노티파이를 가진 스킬은 7개뿐입니다. 기본 공격은 모두 캔슬 윈도우가 없습니다.
| 스토커 | 스킬 ID | 스킬 이름 | 캔슬 시작 | 캔슬 종료 | 윈도우 크기 |
|---|---|---|---|---|---|
| Hilda | SK100201 | Sword Strike | 1.300s | 1.800s | 0.500s |
| Baran | SK130204 | Pulling | 1.276s | 1.700s | 0.424s |
| Baran | SK130206 | Sword Stab | 1.660s | 1.733s | 0.073s |
| Rio | SK140201 | Rapid Stab | 1.513s | 1.833s | 0.320s |
| Lian | SK190207 | Rapid Shot | 2.333s | 2.626s | 0.293s |
| Lian | SK190205 | Back Step | 1.492s | 1.701s | 0.209s |
| Cazimord | SK170202 | Blade Storm | 2.500s | 3.000s | 0.500s |
| Cazimord | SK170201 | Flash (Active) | 1.001s | 1.733s | 0.732s |
캔슬 윈도우가 없는 스토커 (5명):
- Urud, Nave, Clad, Rene, Sinobu
이들은 Activation Order Group 시스템에만 의존하여 스킬 캔슬을 처리합니다. (Section 4.2 참조)
캔슬 윈도우 크기 특징:
- 가장 긴 윈도우: Cazimord Flash_Active (0.732초) - 스택 충전 시스템에 유리
- 가장 짧은 윈도우: Baran Sword Stab (0.073초) - 정밀한 타이밍 요구
- 평균 윈도우: 약 0.4초
4. Blueprint Ability 및 캔슬 시스템
4.1 GA_* Blueprint Ability 구조
모든 스킬과 기본 공격은 UWSGameplayAbility를 상속한 Blueprint 클래스로 구현됩니다. 이 클래스들은 GA_로 시작하며 (GameplayAbility), 스킬 로직을 정의합니다.
UWSGameplayAbility 베이스 클래스
소스 위치: WorldStalker/Source/WorldStalker/AbilitySystem/WSGameplayAbility.h
주요 프로퍼티:
// 0: 그룹 없음, 1이상: 높을 수록 아래 상태를 무시하고, 같은 값이면 서로 교체됨
UPROPERTY(EditDefaultsOnly, Category = "WorldStalker")
uint8 ActivationOrderGroup = 0;
UPROPERTY(EditDefaultsOnly, Category = "WorldStalker")
bool bDisableOrderGroup = false;
UPROPERTY(EditDefaultsOnly, Category = "WorldStalker")
bool bCanSkillCancel = false;
UPROPERTY(EditDefaultsOnly, Category = "WorldStalker")
EWSAbilityActivationTrigger ActivationTrigger = EWSAbilityActivationTrigger::OnceInput;
Ability 클래스 분류
1. 공통 Ability (여러 스토커가 공유):
| Ability 클래스 | 사용 스토커 | 용도 |
|---|---|---|
GA_Attack |
Hilda, Baran, Rio, Clad, Rene, Nave, Sinobu, Cazimord | 기본 공격 (좌클릭) |
GA_Attack_Firearm |
Urud, Lian | 원거리 총기형 기본 공격 (탄약 시스템) |
GA_Attack_Firearm_Reload |
Urud, Lian | 재장전 (Reload 스킬) |
GA_Skill_Common_Blocking |
Hilda, Baran, Clad | 방패 방어 (서브 스킬) |
GA_Skill_Casting_CanMove_CanRelease |
Nave (3개), Clad (3개), Rene (3개), Sinobu, Cazimord | 이동 가능 캐스팅 스킬 |
GA_Skill_Casting_CantMove_CanRelease |
Urud (Make Trap) | 이동 불가 캐스팅 스킬 |
GA_Skill_Casting_Ultimate |
Hilda, Urud, Clad, Rio, Rene, Lian | 궁극기 (공통 로직) |
GA_Skill_Ultimate_Base |
Sinobu | 궁극기 베이스 클래스 |
2. 스토커 전용 Ability (특수 로직 구현):
각 스토커는 고유한 GA_Skill_[Stalker]_[SkillName] 클래스를 가집니다.
Ability 상속 계층
UGameplayAbility (언리얼 엔진 기본 클래스)
└─ UWSGameplayAbility (C++ 베이스 클래스)
├─ GA_WSGameplayAbilityBase_C (Blueprint 베이스)
│ ├─ GA_Attack_C (기본 공격)
│ ├─ GA_Attack_Firearm_C (총기 공격)
│ ├─ GA_Skill_Common_Blocking_C (방어)
│ ├─ GA_Skill_Casting_* (캐스팅 스킬들)
│ └─ GA_Skill_[Stalker]_[Skill]_C (스토커별 스킬)
└─ ...
4.2 Activation Order Group 시스템
Activation Order Group은 스킬 활성화 우선순위를 정의하는 주요 캔슬 메커니즘입니다.
작동 원리
우선순위 규칙:
- 높은 그룹이 낮은 그룹을 캔슬: Group 3 스킬은 Group 1, 2 스킬을 언제든지 중단 가능
- 같은 그룹은 서로 교체 가능: Group 2 스킬끼리는 자유롭게 전환 가능
- 낮은 그룹은 높은 그룹을 캔슬 불가: Group 1 스킬은 Group 2 실행 중 발동 불가
- Group 0은 우선순위 없음: 다른 스킬에 의해 자유롭게 캔슬됨
C++ 코드 구현:
// WSGameplayAbility.h:189-191
uint8 GetActivationOrderGroup() const { return ActivationOrderGroup; }
void SetActivationOrderGroup(uint8 NewActivationOrderGroup) { ActivationOrderGroup = NewActivationOrderGroup; }
bool IsDisableOrderGroup() const { return bDisableOrderGroup; }
우선순위 예시
상황: Hilda가 Counter (Group 3) 실행 중
✅ 가능한 행동:
- Ultimate (Group 4) - 높은 그룹이므로 Counter 캔슬하고 발동
- Counter (Group 3) - 같은 그룹이므로 재사용 가능
❌ 불가능한 행동:
- Sword Strike (Group 2) - 낮은 그룹이므로 Counter 종료 전까지 대기
- 기본 공격 (Group 1) - 낮은 그룹이므로 Counter 종료 전까지 대기
일반적인 그룹 할당 패턴
| Group | 용도 | 예시 |
|---|---|---|
| 0 | 우선순위 없음 | 패시브, 버프, 기본 행동 |
| 2 | 이동/지원 스킬 | Approach, Sway |
| 3 | 방어/반격 스킬 | Counter, Blocking, Parrying, Flash |
| 4 | 일반 스킬 | 대부분의 공격 스킬 |
| 5 | 기본 공격 | 좌클릭 평타, 특수 공격 |
| 9 | 궁극기 | Ultimate 스킬 |
스토커별 Activation Order Group 실제 값
다음은 Blueprint.json에서 추출한 10명 스토커의 실제 ActivationOrderGroup 값입니다.
Hilda (전사):
- Group 4: Bash, SwordStrike
- Group 0: BloodMoon_Active, SteelBlocking
Urud (궁수):
- Group 5: ArrowAttack, MultiShot_Quick, PoisonArrow
- Group 0: CampFire, Explosion_Active, MakeTrap, MultiShot, PierceShot, PoisonArrow_Active, SpeedUp
Nave (마법사):
- Group 9: Escape4 (궁극기)
- Group 4: ManaCharge_Casting
- Group 0: Escape_Active, FireWall_Active, Invisible, MagicMissile_Active, MagicShield, TurnOff, WindForce
Baran (기사):
- Group 9: Decision (궁극기)
- Group 5: Pulling
- Group 4: RockBreaker, Smash, SwordStab
- Group 0: Prepare, Slasher
Rio (암살자):
- Group 5: DroppingAttack
- Group 4: Flashbang, RapidStab, ThrowingDagger
- Group 2: Approach
- Group 0: CatEyes, CorrosionDagger, Sensitive
Clad (성직자):
- Group 0: Gold, HolyCure, HolyLight, HolyShield, HolyWall, Stigma, TurnUndead (모두 지원/버프 스킬)
Rene (소환사):
- Group 5: Scratching
- Group 0: BloodChange, BloodChange_Active, BloodSword_Active, ManaStoneCarnival, PoisonGas_Active, Slow_Active, SummonIfrit_Active, SummonShiva_Active
Sinobu (닌자):
- Group 9: Silence (궁극기)
- Group 5: Shuriken
- Group 4: BombTalisman, MarkingSting, ThunderKick
- Group 3: NinpoGecko_Casting
- Group 0: Deflect, NinpoChange, NinpoFlame, SIlence_Active
Lian (레인저):
- Group 5: BackStepBowAttack, ChargingBow, RapidShot
- Group 4: DarkSouls
- Group 0: CallingRat, MakeWoodCover, ManaStoneSilence_Active, MoreArrow, OneAim
Cazimord (검사):
- Group 9: WingCutter (궁극기)
- Group 4: BladeStorm, Burn, FrontKick, Parrying
- Group 3: Flash
- Group 2: BladeStorm_Perk, Sway, Sway_Perk
- Group 0: Burn_Active
주요 발견:
- 궁극기 (Group 9): Nave, Baran, Sinobu, Cazimord만 보유
- 기본 공격 (Group 5): Urud, Baran, Rio, Rene, Sinobu, Lian이 사용
- Clad와 Rene: 대부분 Group 0 (패시브/지원) 스킬로 구성
- Cazimord: 가장 다양한 Group 분포 (0, 2, 3, 4, 9)
4.3 통합 캔슬 시스템 (OR 조건)
스킬 캔슬은 두 개의 독립적인 메커니즘으로 작동합니다. 둘 중 하나만 만족하면 캔슬이 가능합니다 (OR 조건).
메커니즘 1: Activation Order Group (주요 시스템)
정의 위치: GA_* Blueprint의 Class Defaults (C++ 프로퍼티)
작동 시점: 언제든지 (애니메이션 재생 중 어느 구간이든)
조건:
IF (새 스킬의 ActivationOrderGroup >= 현재 스킬의 ActivationOrderGroup)
THEN 캔슬 가능
특징:
- 우선순위 기반 시스템
- 프레임 단위 정밀 제어 불필요
- 대부분의 캔슬 처리 담당
메커니즘 2: ANS_SkillCancel_C (보조 시스템)
정의 위치: AnimMontage의 Notify State
작동 시점: 노티파이가 활성화된 시간 구간 (TriggerTime ~ TriggerTime+Duration)
조건:
IF (현재 시간이 ANS_SkillCancel_C 구간 내)
AND (새 스킬의 ActivationOrderGroup >= 현재 스킬의 ActivationOrderGroup)
THEN 캔슬 가능
특징:
- 타이밍 기반 윈도우
- 스킬의 "자연스러운 종료" 구간 정의
- 같은 우선순위 스킬도 이 구간에서는 캔슬 가능
통합 로직 (의사 코드)
bool CanCancelCurrentSkill(GA_NewSkill, GA_CurrentSkill, CurrentTime)
{
// 조건 1: Activation Order Group 우선순위 체크
bool bHigherPriority = (GA_NewSkill.ActivationOrderGroup > GA_CurrentSkill.ActivationOrderGroup);
// 조건 2: ANS_SkillCancel_C 윈도우 체크
bool bInCancelWindow = false;
if (GA_CurrentSkill.CurrentMontage->HasSkillCancelNotify())
{
float CancelStart = SkillCancelNotify.TriggerTime;
float CancelEnd = CancelStart + SkillCancelNotify.Duration;
bInCancelWindow = (CurrentTime >= CancelStart && CurrentTime <= CancelEnd);
// 캔슬 윈도우 내에서는 같은 우선순위도 허용
if (bInCancelWindow && GA_NewSkill.ActivationOrderGroup >= GA_CurrentSkill.ActivationOrderGroup)
return true;
}
// OR 조건: 둘 중 하나만 만족하면 캔슬 가능
return bHigherPriority || bInCancelWindow;
}
실전 예시
예시 1: Hilda - Sword Strike 스킬 사용 중 (Group 2)
| 상황 | 시간 | 새 입력 | 캔슬 가능? | 이유 |
|---|---|---|---|---|
| 스킬 시작 | 0.5초 | 기본 공격 (Group 1) | ❌ | 낮은 우선순위 |
| 스킬 시작 | 0.5초 | Counter (Group 3) | ✅ | 높은 우선순위 (메커니즘 1) |
| 캔슬 윈도우 | 1.4초 | 다른 스킬 (Group 2) | ✅ | ANS_SkillCancel_C 구간 (메커니즘 2) |
| 캔슬 윈도우 | 1.4초 | 기본 공격 (Group 1) | ❌ | 여전히 낮은 우선순위 |
| 스킬 종료 | 1.9초 | 모든 스킬 | ✅ | 스킬 완전 종료 |
예시 2: Urud - Multi Shot 스킬 (ANS_SkillCancel_C 없음)
| 상황 | 새 입력 | 캔슬 가능? | 이유 |
|---|---|---|---|
| 스킬 실행 중 | 일반 스킬 (같은 Group) | ❌ | ANS_SkillCancel_C 없음, 같은 우선순위 |
| 스킬 실행 중 | Ultimate (Group 4) | ✅ | 높은 우선순위 (메커니즘 1만 작동) |
4.4 주요 Ability 구현 분석
이전에 추출한 Blueprint.json 데이터를 기반으로 주요 Ability의 구조를 분석합니다.
GA_Attack (기본 공격)
사용 스토커: Hilda, Baran, Rio, Clad, Rene, Nave, Sinobu, Cazimord
부모 클래스: GA_WSGameplayAbilityBase_C
EventGraph 노드 수: 70개 (중간 복잡도)
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
ComboIndex |
Int | 현재 콤보 인덱스 (0~2) |
MaxComboCount |
Int | 최대 콤보 수 (기본 3) |
ComboInputBuffer |
Bool | 콤보 입력 버퍼 (선입력 지원) |
로직:
- 장착한 무기의
montages배열에서 ComboIndex에 해당하는 몽타주 재생 - 콤보 윈도우 내에 재입력 시 다음 콤보로 체인
- 최대 콤보 도달 또는 일정 시간 경과 시 ComboIndex 리셋
GA_Attack_Firearm (총기형 기본 공격)
사용 스토커: Urud, Lian
부모 클래스: GA_Attack_C
EventGraph 노드 수: 85개 (높은 복잡도)
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
AmmoTag |
GameplayTag | 탄약 카운트 태그 (Character.State.Ammo) |
MaxAmmo |
Int | 최대 탄약 수 |
bAutoReload |
Bool | 탄약 소진 시 자동 재장전 |
특수 로직:
- 공격 시 AmmoTag 값을 1 감소
- 탄약이 0이면 공격 불가, 자동으로 Reload 스킬 트리거
- Reload 스킬 완료 시 AmmoTag를 MaxAmmo로 복구
예시 - Urud:
초기 탄약: 6발
발사 1~6발: AmmoTag = 6 → 5 → 4 → 3 → 2 → 1 → 0
탄약 소진: GA_Attack_Firearm_Reload 자동 실행
재장전 완료: AmmoTag = 6으로 복구
GA_Skill_Common_Blocking (방패 방어)
사용 스토커: Hilda, Baran, Clad
EventGraph 노드 수: 112개 (매우 높은 복잡도)
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
BlockingStaminaCost |
Float | 방어 시 스태미나 소모량 |
BlockingDamageReduction |
Float | 피해 감소율 (%) |
bPerfectBlockWindow |
Bool | 완벽 방어 윈도우 활성화 |
특수 로직:
- 버튼을 누르고 있는 동안 방어 상태 유지 (WhileInput 트리거)
- 피격 시 BlockingDamageReduction만큼 피해 감소
- 스태미나가 0이면 방어 해제
- 완벽 방어 타이밍 성공 시 스태미나 소모 없음
GA_Skill_Casting_CanMove_CanRelease (이동 가능 캐스팅)
사용 스토커: Nave (3개 스킬), Clad (3개 스킬), Rene (3개 스킬), Sinobu, Cazimord
EventGraph 노드 수: 68개
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
CastingTime |
Float | 캐스팅 시간 (DT_Skill에서 가져옴) |
bCanMoveWhileCasting |
Bool | 캐스팅 중 이동 가능 (true) |
bCanRelease |
Bool | 버튼을 떼면 즉시 발동 (차징) |
특수 로직:
- 버튼 누름: 캐스팅 시작 (몽타주 재생)
- 캐스팅 중 이동 속도 감소 (GE_WalkSpeed 적용)
- 버튼을 떼거나 CastingTime 경과 시 스킬 발동
- 캐스팅 중 다른 높은 우선순위 스킬로 캔슬 가능
4.5 스토커별 특수 시스템 구현
Hilda - Counter (반격 시스템)
Ability: GA_Skill_Knight_Counter_C
메커니즘:
- Counter 스킬 발동 시 짧은 시간 동안 "반격 판정" 상태
- 이 상태에서 피격 시 피해 무효화 + 자동 반격
- 반격 성공 시 추가 피해 (DT_Skill의 skillDamageRate 배율 적용)
AnimMontage: AM_PC_Hilda_B_Skill_Counter (Duration: 2.567초)
- 반격 판정 구간: 0.3~0.8초 (0.5초 윈도우)
- ANS_SkillCancel_C 없음 (강제로 끝까지 재생)
Urud & Lian - Reload 시스템
Ability: GA_Attack_Firearm_Reload_C
메커니즘:
- Reload 스킬 사용 시 재장전 몽타주 재생
- 재장전 완료 노티파이에서 AmmoTag 복구
- 재장전 중에는 공격 불가 (Blocking 상태)
특수 사항:
- Urud: 탄약 6발, Reload 2.0초
- Lian: 탄약 6발, Reload 2.0초 + Precision Aim (조준 시스템)
Lian의 Precision Aim:
- 조준 버튼 누르면 줌 + 이동 속도 대폭 감소
- 조준 중 명중률 증가 (히트박스 확대)
Rio - Chain Score 시스템 (3 스택)
Ability: GA_Skill_Rio_DroppingAttack_C (서브 스킬)
EventGraph 노드 수: 42개
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
ChainScoreTag |
GameplayTag | 체인 스코어 태그 (Character.State.ChainScore) |
MaxChainScore |
Int | 최대 스택 (3) |
ChainScoreDamageBonus |
Float | 스택당 피해 증가율 |
메커니즘:
- Dropping Attack (공중 낙하 공격) 성공 시 ChainScore +1
- 스택이 쌓일수록 다음 공격의 피해량 증가
- 최대 3스택 유지, 일정 시간 경과 또는 피격 시 리셋
예시:
Dropping Attack 성공 1회: ChainScore = 1, 다음 공격 피해 +10%
Dropping Attack 성공 2회: ChainScore = 2, 다음 공격 피해 +20%
Dropping Attack 성공 3회: ChainScore = 3, 다음 공격 피해 +30% (최대)
Rene - Spirit 소환 및 Lifesteal
Ability: GA_Skill_Rene_SummonIfrit_C, GA_Skill_Rene_SummonShiva_C
EventGraph 노드 수: Summon Ifrit (58개), Summon Shiva (55개)
메커니즘:
- 소환 스킬 사용 시 AI 제어 소환수 스폰
- 소환수는 독립적으로 적 공격
- Rene의 공격에 Lifesteal 효과 (GE_Lifesteal 적용)
Lifesteal:
- 피해량의 일정 %를 HP로 회복
- GameplayEffect로 구현 (Section 5 참조)
Sinobu - Shuriken 충전 시스템
Ability: GA_Skill_Sinobu_Shuriken_C (서브 스킬)
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
ShurikenChargeTag |
GameplayTag | 수리검 충전 태그 |
MaxShurikenCharge |
Int | 최대 충전 수 (3) |
메커니즘:
- 수리검 발사 시 ChargeTag -1
- 자동으로 시간 경과에 따라 충전 (1초당 1개)
- 충전이 0이면 발사 불가
Swap 인술 (SK180205 - Ninpo Change):
- 적 위치와 자신의 위치를 순간 교환 (텔레포트)
- 중력 조작 (Gravity = 0) 구간 존재
Lian - Charging Bow (3스택 충전)
Ability: GA_Skill_Lian_ChargingBow_C (서브 스킬)
EventGraph 노드 수: 116개 (가장 복잡한 서브 스킬)
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
ChargeLevel |
Int | 충전 레벨 (0~3) |
ChargeTime |
Float | 레벨당 충전 시간 |
ChargeDamageMultiplier |
Array | 레벨별 피해 배율 |
메커니즘:
- 버튼 누름: 충전 시작
- 0.5초마다 ChargeLevel +1 (최대 3)
- 버튼 떼기: 현재 ChargeLevel에 해당하는 피해로 화살 발사
- ChargeLevel 3 (만충전): 피해 2배 + 관통 효과
피해 배율:
Level 0: 0.7x (즉발)
Level 1: 1.0x
Level 2: 1.5x
Level 3: 2.0x + 관통
Cazimord - Flash 스택 & Parrying
Flash 시스템 (SK170201):
Ability: GA_Skill_Cazimord_Flash_C
주요 변수:
| 변수명 | 타입 | 설명 |
|---|---|---|
FlashStackTag |
GameplayTag | Flash 스택 태그 |
MaxFlashStack |
Int | 최대 스택 (3) |
메커니즘:
- Flash 스킬 사용 시 준비 몽타주 재생 (1.0초)
- 스택이 있으면 Flash_Active 몽타주 재생 (1.733초)
- Flash_Active는 빠른 돌진 + 피해
- 스택은 Parrying 성공 시 충전
ANS_SkillCancel_C: Flash_Active에만 존재 (1.001~1.733초, 0.732초 윈도우)
Parrying 시스템 (SK170101):
Ability: GA_Skill_Cazimord_Parrying_C
메커니즘:
- Parrying 발동 시 짧은 패링 판정 구간 (0.2초)
- 패링 성공 시:
- 적 피해 무효화
- 자동 반격 (높은 피해)
- FlashStackTag +1
- Parrying 스킬 쿨타임 즉시 리셋 (자기 자신 쿨타임 감소)
특수 사항:
- Parrying은 쿨타임 감소 로직을 가진 유일한 스킬
- 패링 실패 시에도 쿨타임 적용 (리스크-리워드)
5. GameplayEffect 메커니즘
5.1 GameplayEffect 개요
GameplayEffect는 언리얼 엔진의 Gameplay Ability System에서 캐릭터의 Attribute (HP, MP, 공격력 등)를 수정하는 메커니즘입니다. 모든 피해, 회복, 버프, 디버프는 GameplayEffect로 구현됩니다.
주요 GameplayEffect 타입
| 타입 | 지속 시간 | 용도 | 예시 |
|---|---|---|---|
| Instant | 즉시 적용 | 피해, 즉시 회복 | GE_Attack_Physical (공격 피해) |
| Duration | 정해진 시간 | 버프/디버프 | GE_Buff_AttackSpeed (5초간 공격 속도 증가) |
| Infinite | 영구 (수동 제거) | 장비 효과, 패시브 | GE_Equip_Weapon (무기 장착 보너스) |
5.2 주요 GameplayEffect 클래스
GE_Attack_* (공격 피해)
DT_Skill의 gameplayEffectSet 또는 GA_ Blueprint에서 적용*
예시 - GE_Attack_Physical:
- 타입: Instant
- Modifier: HP -= (공격력 × skillDamageRate × 속성 배율)
- 적용 시점: AnimNotifyState_AttackWithEquip 히트 판정 성공 시
피해 계산 공식 (일반적):
최종 피해 = 기본 공격력 × skillDamageRate × AddNormalAttackPer × (1 - 방어율) × 크리티컬 배율 × 속성 저항
GE_Skill_* (스킬 효과)
스킬별로 고유한 GameplayEffect를 가질 수 있습니다.
예시 - Hilda의 Sword Strike (SK100201):
- GE_Skill_Hilda_SwordStrike: Lightning 속성 피해
- Lightning 저항 적용:
FinalDamage × (1 - Target.LightningResistancePer)
예시 - Rene의 Lifesteal:
- GE_Lifesteal_Rene: Duration 타입, 일정 시간 동안 모든 공격에 흡혈 효과
- Modifier: HP += (DamageDealt × LifestealRate)
GE_Buff/Debuff_* (버프/디버프)
예시 - GE_Buff_AttackSpeed:
- 타입: Duration (5초)
- Modifier: AttackSpeed += 20%
- 시각 효과: 버프 아이콘 표시
예시 - GE_Debuff_Poison (Urud의 Poison Arrow):
- 타입: Duration (10초)
- Modifier: HP -= 10 (매 1초마다, Periodic)
- 시각 효과: 독 이펙트 파티클
GE_Cooldown_* (쿨타임)
DT_Skill의 coolTime 값을 기반으로 자동 생성됩니다.
메커니즘:
- 스킬 사용 시 GE_Cooldown_[SkillID] 적용
- GameplayTag:
Cooldown.Skill.[SkillID]부여 - coolTime 초 경과 후 자동 제거
- 태그가 있는 동안 해당 스킬 사용 불가
쿨타임 감소:
- WSGameplayAbility의
ReduceSkillCoolTime함수 사용 - 특정 룬/장비 효과로 쿨타임 % 감소 가능
GE_ManaCost_* (마나 소모)
DT_Skill의 skillManaCost 값을 기반으로 적용됩니다.
메커니즘:
- 스킬 CommitAbility 단계에서 마나 체크
- 마나 부족 시 스킬 발동 실패
- 마나 충분 시 GE_ManaCost 적용하여 MP 감소
5.3 GameplayEffectSet 구조
DT_Skill의 gameplayEffectSet 배열은 여러 GameplayEffect를 순차적으로 적용합니다.
구조:
"gameplayEffectSet": [
{
"applyTrigger": "OnActivation",
"gameplayEffectClass": "/Game/Blueprints/Effects/GE_Skill_Buff.GE_Skill_Buff_C",
"targetType": "Self"
},
{
"applyTrigger": "OnHit",
"gameplayEffectClass": "/Game/Blueprints/Effects/GE_Attack_Damage.GE_Attack_Damage_C",
"targetType": "Target"
}
]
applyTrigger 타입:
OnActivation: 스킬 활성화 시 즉시OnHit: 타격 성공 시OnEnd: 스킬 종료 시Periodic: 주기적으로
targetType:
Self: 시전자에게 적용Target: 타격 대상에게 적용Area: 범위 내 모든 대상
5.4 특수 GameplayEffect 예시
Nave의 Fire Wall (지속 피해 장판)
메커니즘:
- Fire Wall 스킬 사용 시 바닥에 화염 장판 생성
- 장판 범위 내 적에게 GE_Debuff_FireWall_Periodic 적용
- Periodic 효과: 매 0.5초마다 Fire 속성 피해
GameplayEffect:
- 타입: Duration (5초)
- Period: 0.5초
- Modifier: HP -= (BaseDamage × 0.2)
Baran의 Pulling (중력 조작)
메커니즘:
- Pulling 스킬 적중 시 GE_Pulling_Gravity 적용
- 적의 Gravity를 음수로 변경 (끌어당김)
- 0.5초 동안 적을 Baran 방향으로 이동
GameplayEffect:
- 타입: Duration (0.5초)
- Modifier: Gravity = -1000 (강제 이동)
- Physics: AddImpulse (Baran 방향)
Clad의 Holy Cure (힐링)
메커니즘:
- Holy Cure 스킬 사용 시 GE_Heal_Holy 적용
- 자신 또는 아군의 HP 회복
GameplayEffect:
- 타입: Instant
- Modifier: HP += (HealAmount × WIS)
- targetType: Self 또는 FriendlyTarget
6. DT_Skill 특수 케이스
6.1 Nave의 궁극기 - Liberation (Escape 4)
스킬 ID: SK120301
특수 사항: 대부분의 스킬은 AnimMontage의 노티파이(AnimNotifyState_AttackWithEquip)에서 피해를 처리하지만, Nave의 궁극기 'Liberation'은 DT_Skill의 데이터에서 직접 피해를 정의합니다.
일반 스킬의 피해 처리 (일반적 케이스)
흐름:
1. DT_Skill에서 skillDamageRate 정의 (예: 1.3)
2. AnimMontage의 AnimNotifyState_AttackWithEquip 노티파이 실행
3. 노티파이에서 AttackTag (Event.Attack.Skill) 트리거
4. GA_* Blueprint에서 skillDamageRate를 곱하여 피해 계산
5. GE_Attack_* GameplayEffect 적용
예시 - Hilda Sword Strike:
DT_Skill: skillDamageRate = 1.3
AnimMontage: AnimNotifyState_AttackWithEquip (TriggerTime: 0.6초)
Blueprint: ApplyAttackEffectToTarget 함수 호출
GameplayEffect: GE_Attack_Lightning 적용
최종 피해 = 기본 공격력 × 1.3 × Lightning 배율
Nave 궁극기의 피해 처리 (특수 케이스)
흐름:
1. DT_Skill의 gameplayEffectSet에 직접 피해 GameplayEffect 정의
2. AnimMontage에는 피해 노티파이 없음 (시각 효과만)
3. GA_Skill_Nave_Escape4 Blueprint에서 gameplayEffectSet 직접 적용
4. 범위 내 모든 적에게 피해 (Area 타겟)
DT_Skill 데이터 (SK120301):
{
"RowName": "SK120301",
"stalkerName": "nave",
"bIsUltimate": true,
"skillName": "Escape 4",
"skillDamageRate": 1.0,
"skillAttackType": "MagicalSkill",
"skillElementType": "None",
"useMontages": [
"/Game/_Art/_Character/PC/Nave/AnimMontage/Ultimate/AM_PC_Nave_B_Skill_Escape4.AM_PC_Nave_B_Skill_Escape4"
],
"abilityClass": "/Game/Blueprints/Characters/Nave/GA_Skill_Nave_Escape4.GA_Skill_Nave_Escape4_C",
"gameplayEffectSet": [
{
"applyTrigger": "OnActivation",
"gameplayEffectClass": "/Game/Blueprints/Effects/GE_Skill_Nave_Liberation.GE_Skill_Nave_Liberation_C",
"targetType": "Area"
}
]
}
GE_Skill_Nave_Liberation:
- 타입: Instant
- 범위: 반경 500 units
- Modifier: HP -= (MagicPower × 1.0) × 4회 (4번의 텔레포트 각각 피해)
- 특징: 텔레포트 이동 경로에 있는 모든 적 피해
AnimMontage (AM_PC_Nave_B_Skill_Escape4):
- Duration: 3.5초
- ANS_SkillCancel_C: 없음
- 피해 판정 노티파이: 없음 (GameplayEffect에서 직접 처리)
- 시각 효과 노티파이만 존재 (4회 텔레포트 이펙트)
왜 이렇게 구현했는가?
일반 스킬 방식의 한계:
- AnimNotifyState_AttackWithEquip은 무기 궤적 기반 히트 판정
- Nave의 궁극기는 텔레포트 경로 전체가 피해 범위
- 무기가 없고, 정해진 궤적이 없음
gameplayEffectSet 직접 사용 장점:
- 복잡한 범위 판정을 GameplayEffect 로직으로 처리
- 4회 텔레포트의 각 경로마다 별도 피해 적용 가능
- AnimMontage와 피해 로직 분리로 유연성 확보
6.2 Urud의 궁극기 - Explosion (범위 피해)
스킬 ID: SK110301
특수 사항: 투척한 돌이 지면 또는 적 적중 시 폭발하여 범위 피해를 줍니다.
메커니즘:
- 궁극기 활성화 시 투사체(돌) 스폰
- 투사체 충돌 시 Explosion Actor 생성
- Explosion Actor의 Overlap 이벤트에서 범위 내 적 검색
- 각 적에게 GE_Skill_Urud_Explosion 적용
특징:
- 피해는 AnimMontage가 아닌 투사체 충돌 이벤트에서 처리
- DT_Skill의 skillDamageRate는 기본 배율로 사용
- 범위 중심부일수록 높은 피해 (거리 기반 감쇠)
7. 코드-어셋 통합 흐름
7.1 스킬 실행 전체 흐름
스킬이 입력부터 피해 적용까지 거치는 전체 과정을 정리합니다.
[1] 입력 처리
↓
[2] DT_CharacterStat에서 스킬 ID 조회
↓
[3] DT_Skill에서 스킬 데이터 로드
├─ skillDamageRate
├─ coolTime
├─ skillManaCost
├─ useMontages
└─ abilityClass
↓
[4] GA_* Blueprint Ability 실행
├─ CanActivateAbility: 쿨타임/마나 체크
├─ ActivateAbility: 스킬 시작
│ ├─ Activation Order Group 비교
│ └─ 현재 스킬 캔슬 여부 결정
├─ CommitAbility: 마나/쿨타임 소모 확정
│ ├─ GE_ManaCost 적용
│ └─ GE_Cooldown 적용
└─ PlayMontage: AnimMontage 재생
↓
[5] AnimMontage 재생
├─ ANS_AttackState_C: 공격 상태 활성화
├─ AnimNotifyState_AttackWithEquip: 히트 판정
│ ├─ AttackTag 기반 이벤트 트리거
│ └─ 범위 내 적 검색
├─ ANS_SkillCancel_C: 캔슬 윈도우 활성화
└─ AN_SetAutoTarget_C: 자동 타게팅
↓
[6] 피해 계산 (GA_* Blueprint)
├─ FindSkillDataRow: DT_Skill 데이터 재조회
├─ CalculateSkillRate: 최종 피해 배율 계산
│ ├─ skillDamageRate (기본)
│ ├─ AddNormalAttackPer (몽타주)
│ ├─ 장비 보정 (EquipSkillModify)
│ └─ 룬 보정
└─ ApplyAttackEffectToTarget: GameplayEffect 적용
↓
[7] GameplayEffect 적용
├─ GE_Attack_* 또는 GE_Skill_*
├─ Attribute Modifier 실행
│ ├─ Target HP 감소
│ ├─ 속성 저항 계산
│ └─ 크리티컬 판정
└─ 시각/사운드 효과 재생
↓
[8] 스킬 종료
├─ EndAbility: Ability 정리
│ ├─ ActiveGameplayEffectHandle 제거
│ └─ 카메라 모드 해제
└─ 다음 입력 대기
7.2 캔슬 판정 상세 흐름
스킬 실행 중 새로운 입력이 들어왔을 때의 판정 과정:
새 스킬 입력 (예: Sword Strike → Counter)
↓
[1] 현재 실행 중인 Ability 확인
├─ CurrentAbility: GA_Skill_Hilda_SwordStrike
├─ CurrentAbility.ActivationOrderGroup: 2
└─ CurrentTime: 0.5초 (몽타주 재생 중)
↓
[2] 새 Ability 정보 확인
├─ NewAbility: GA_Skill_Knight_Counter
└─ NewAbility.ActivationOrderGroup: 3
↓
[3] 캔슬 가능 여부 판정 (OR 조건)
├─ 조건 A: Activation Order Group 비교
│ └─ 3 > 2 → TRUE (높은 우선순위)
├─ 조건 B: ANS_SkillCancel_C 윈도우 체크
│ ├─ CurrentMontage: AM_PC_Hilda_B_Skill_SwordStrike
│ ├─ SkillCancel 구간: 1.3~1.8초
│ └─ CurrentTime 0.5초 < 1.3초 → FALSE (윈도우 밖)
└─ 최종 결과: TRUE (조건 A 만족)
↓
[4] 캔슬 실행
├─ CurrentAbility.EndAbility(bWasCancelled=true)
├─ NewAbility.ActivateAbility()
└─ Counter 몽타주 재생 시작
7.3 C++ 코드와 어셋의 연동 지점
| C++ 클래스 | 어셋 | 연동 방법 |
|---|---|---|
UWSGameplayAbility |
GA_* Blueprint | Blueprint이 C++ 클래스 상속 |
ActivationOrderGroup (C++ 변수) |
GA_* Class Defaults | Blueprint 에디터에서 값 설정 |
FSkillDataRow (C++ 구조체) |
DT_Skill DataTable | DataTable의 RowStructure로 사용 |
ApplyAttackEffectToTarget (C++ 함수) |
AnimNotifyState_AttackWithEquip | 노티파이에서 함수 호출 |
UGameplayEffect |
GE_* Blueprint | GameplayEffect 서브클래스 |
핵심 연동 함수:
// WSGameplayAbility.cpp
FSkillDataRow* UWSGameplayAbility::FindSkillDataRow(FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo) const
{
// DT_Skill에서 현재 스킬의 행 데이터 조회
// abilityClass 경로로 역참조
}
void UWSGameplayAbility::ApplyAttackEffectToTarget(FGameplayAbilityTargetDataHandle TargetData, FGameplayTag InAttackTag, bool& bAttackFailMotion)
{
// AnimMontage 노티파이에서 호출
// DT_Skill 데이터 + 장비 보정 + 룬 보정 통합 계산
// 최종 GameplayEffect 적용
}
8. JSON 사용 가이드
8.1 JSON 파일 구조 이해
익스포트된 JSON 파일들은 다음과 같은 구조를 가집니다:
DataTable.json:
[
{
"AssetName": "DT_CharacterStat",
"AssetPath": "/Game/Blueprints/DataTable/DT_CharacterStat.DT_CharacterStat",
"RowStructure": "CharacterStatData",
"Rows": [
{
"RowName": "hilda",
"Data": { ... }
}
]
}
]
AnimMontage.json:
[
{
"AssetName": "AM_PC_Hilda_B_Skill_SwordStrike",
"AssetPath": "/Game/_Art/_Character/PC/Hilda/AnimMontage/Skill/AM_PC_Hilda_B_Skill_SwordStrike.AM_PC_Hilda_B_Skill_SwordStrike",
"SequenceLength": 1.8,
"Sections": [...],
"AnimNotifies": [...]
}
]
Blueprint.json:
[
{
"AssetName": "GA_Skill_Hilda_SwordStrike",
"AssetPath": "/Game/Blueprints/Characters/Hilda/GA_Skill_Hilda_SwordStrike.GA_Skill_Hilda_SwordStrike",
"ParentClass": "GA_WSGameplayAbilityBase_C",
"Variables": [...],
"Functions": [...],
"EventGraphs": [...]
}
]
8.2 데이터 추출 방법
Python을 사용한 JSON 파싱 예시
import json
# 1. DataTable에서 특정 스토커의 스킬 목록 조회
with open('DataTable.json', 'r', encoding='utf-8') as f:
datatables = json.load(f)
# DT_CharacterStat 찾기
dt_char_stat = next((dt for dt in datatables if dt['AssetName'] == 'DT_CharacterStat'), None)
# Hilda의 스킬 목록
hilda_data = next((row for row in dt_char_stat['Rows'] if row['RowName'] == 'hilda'), None)
default_skills = hilda_data['Data']['defaultSkills'] # ["SK100201", "SK100202", "SK100204"]
# 2. DT_Skill에서 스킬 상세 정보 조회
dt_skill = next((dt for dt in datatables if dt['AssetName'] == 'DT_Skill'), None)
for skill_id in default_skills:
skill_data = next((row for row in dt_skill['Rows'] if row['RowName'] == skill_id), None)
print(f"{skill_id}: {skill_data['Data']['skillName']}, Damage: {skill_data['Data']['skillDamageRate']}")
특정 노티파이를 가진 AnimMontage 검색
with open('AnimMontage.json', 'r', encoding='utf-8') as f:
montages = json.load(f)
# ANS_SkillCancel_C를 가진 모든 몽타주 찾기
cancel_montages = []
for montage in montages:
for notify in montage.get('AnimNotifies', []):
if notify.get('NotifyStateClass') == 'ANS_SkillCancel_C':
cancel_montages.append({
'montage': montage['AssetName'],
'start': notify['TriggerTime'],
'duration': notify['Duration']
})
for item in cancel_montages:
print(f"{item['montage']}: {item['start']}~{item['start']+item['duration']}초")
8.3 크로스 레퍼런스 (어셋 간 연결 추적)
스킬 하나의 전체 정보를 추적하는 방법:
# 1. DT_CharacterStat에서 스토커 → 스킬 ID
stalker_name = 'hilda'
skill_id = 'SK100201' # DT_CharacterStat.hilda.defaultSkills[0]
# 2. DT_Skill에서 스킬 ID → 몽타주 경로, Ability 경로
skill_row = find_skill_by_id(skill_id)
montage_paths = skill_row['Data']['useMontages']
ability_path = skill_row['Data']['abilityClass']
# 3. AnimMontage.json에서 몽타주 경로 → 타이밍 데이터
montage_asset_name = montage_paths[1].split('.')[-1] # "AM_PC_Hilda_B_Skill_SwordStrike"
montage_data = find_montage_by_name(montage_asset_name)
# ANS_SkillCancel_C 추출
cancel_notify = next((n for n in montage_data['AnimNotifies']
if n.get('NotifyStateClass') == 'ANS_SkillCancel_C'), None)
# 4. Blueprint.json에서 Ability 경로 → 로직 구조
ability_asset_name = ability_path.split('/')[-1].split('.')[0] # "GA_Skill_Hilda_SwordStrike"
ability_data = find_blueprint_by_name(ability_asset_name)
# 최종 통합 정보
skill_info = {
'id': skill_id,
'name': skill_row['Data']['skillName'],
'damage_rate': skill_row['Data']['skillDamageRate'],
'cooldown': skill_row['Data']['coolTime'],
'montage_duration': montage_data['SequenceLength'],
'cancel_window': f"{cancel_notify['TriggerTime']}~{cancel_notify['TriggerTime']+cancel_notify['Duration']}" if cancel_notify else "없음",
'ability_complexity': len(ability_data['EventGraphs'][0]['Nodes'])
}
8.4 주의사항
1. 라인 번호 참조 금지:
- JSON 파일은 익스포트할 때마다 순서가 바뀔 수 있음
- 항상 AssetName, RowName으로 검색
2. 경로 형식 이해:
언리얼 경로: /Game/Blueprints/Abilities/GA_Attack.GA_Attack_C
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 에셋 경로
^^^^^^^^^^^ 클래스 이름
JSON에서 찾을 때: "GA_Attack" (확장자 제외)
3. Blueprint Class Defaults 값 (ActivationOrderGroup) 포함:
- EventGraph 노드 구조: JSON 포함
- Class Defaults 값 (ActivationOrderGroup): JSON에 포함됨 (Variables 배열 내)
- 추출 방법: Blueprint의 Variables 배열에서 "Name": "ActivationOrderGroup" 검색하여 DefaultValue 확인
4. 몽타주 경로 추출:
# DT_Skill.useMontages 배열
useMontages = [
"/Script/Engine.AnimMontage'/Game/_Art/_Character/PC/Hilda/AnimMontage/Skill/AM_PC_Hilda_B_Skill_Ready.AM_PC_Hilda_B_Skill_Ready'",
"/Script/Engine.AnimMontage'/Game/_Art/_Character/PC/Hilda/AnimMontage/Skill/AM_PC_Hilda_B_Skill_SwordStrike.AM_PC_Hilda_B_Skill_SwordStrike'"
]
# 몽타주 이름 추출
montage_names = [path.split('/')[-1].split('.')[0] for path in useMontages]
# ["AM_PC_Hilda_B_Skill_Ready", "AM_PC_Hilda_B_Skill_SwordStrike"]
8.5 유용한 분석 패턴
패턴 1: 모든 스킬의 평균 쿨타임 계산
skills = [row for dt in datatables if dt['AssetName'] == 'DT_Skill' for row in dt['Rows']]
avg_cooldown = sum(skill['Data']['coolTime'] for skill in skills) / len(skills)
패턴 2: 특정 스토커의 총 EventGraph 노드 수 (복잡도)
stalker_abilities = [bp for bp in blueprints if 'Hilda' in bp['AssetName']]
total_nodes = sum(len(eg['Nodes']) for bp in stalker_abilities for eg in bp['EventGraphs'])
패턴 3: ANS_SkillCancel_C 보유율
total_montages = len(montages)
cancel_montages = len([m for m in montages if any(n.get('NotifyStateClass') == 'ANS_SkillCancel_C' for n in m.get('AnimNotifies', []))])
cancel_rate = (cancel_montages / total_montages) * 100
문서 종료
본 문서는 언리얼 엔진 에셋(DataTable, AnimMontage, Blueprint)을 JSON으로 익스포트하여 분석한 WorldStalker 전투 로직 시스템의 기술 문서입니다.
작성 정보:
- 작성일: 2025-10-23
- 익스포트 데이터:
DS-전투밸런스_분석자료/20251023_114317/ - 분석 대상: 10명의 스토커 (Hilda, Urud, Nave, Baran, Rio, Clad, Rene, Sinobu, Lian, Cazimord)
추가 참고 문서:
DS-기획_메뉴얼-전투_로직.md: 전투 로직 기획 문서DS-Asset_Export_to_JSON.md: Asset Export 시스템 가이드