Youngki Jeong | Game Dev Lab
HomeProjectsEvidenceJourneyAbout
SearchGitHub글쓰기

Youngki Jeong | Game Dev Lab

Unreal C++ 게임개발 포트폴리오 & 개발 기록

Projects·Evidence·Journey·About·GitHub Portfolio·GitHub

빠른 검색

프로젝트, Evidence, 디버깅 노트, 학습 기록을 검색합니다.

← 목록으로
← 목록으로
RIT-B02

Experience에서 Gameplay Ready까지

2026년 9월 7일
·
JEONGYOUNGKI
Description

Experience → PawnData → ASC → AbilitySet → Input으로 이어지는 Unreal Gameplay 초기화 흐름과 책임을 정리한 글입니다.

Project

RiteSeekers

ArticleType

Runtime Flow

SourceBoundary

Reference

EvidenceLevel

Source

Priority

A

Tags

GameplayFramework

ProofType

Source

Audience

Technical Interviewer

CareerTrack

Gameplay

목차

RIT-B02 | RiteSeekers — Experience에서 Gameplay Ready까지

처음에는 게임이 시작될 때의 초기화를 비교적 단순하게 생각했습니다.

Text
Character Spawn
→ BeginPlay
→ 필요한 기능 초기화
→ Gameplay 시작

Pawn이 생성되고 BeginPlay가 호출되면 ASC를 연결하고 Ability와 Input을 준비하면 된다고 생각했습니다.

그런데 Lyra Source와 RiteSeekers 설정을 같이 따라가 보니 Pawn이 화면에 나타나는 것과 실제로 Ability와 Input까지 사용할 수 있는 상태가 되는 것은 같은 시점이 아니었습니다.

제가 따라간 흐름은 대략 다음과 같습니다.

Text
Experience
→ PawnData
→ AbilitySet / ASC
→ PawnExtension
→ Current Pawn 연결
→ InputConfig
→ Ability Input
→ GameplayReady

이 흐름을 보고 나서 Character Spawn을 Gameplay 초기화의 끝으로 보지 않게 됐습니다.


Experience에서 PawnData까지

작은 프로젝트에서는 Pawn의 BeginPlay에서 필요한 초기화를 한 번에 처리하는 방식도 충분히 사용할 수 있습니다.

저도 처음에는 이런 그림을 생각했습니다.

Text
BeginPlay
→ ASC 연결
→ Ability 부여
→ Input 바인딩

Lyra 계열 Source에서는 Pawn, PlayerState, ASC, InputComponent가 항상 같은 순간에 준비된다고 가정하지 않았습니다.

조금 더 풀어보면 이런 상태들이 이어집니다.

Text
Experience Loaded
→ PawnData 결정
→ PlayerState에 PawnData 설정
→ AbilitySet Grant
→ Pawn Spawn / PawnData 전달
→ PawnExtension InitState 진행
→ ASC와 Current Pawn 연결
→ InputConfig 기반 입력 바인딩
→ ASC 입력 처리
→ GameplayReady

여기서 화살표는 하나의 함수가 위에서 아래로 차례대로 호출되는 Call Stack을 뜻하지 않습니다.

Experience, PlayerState, PawnExtension, HeroComponent가 각자 필요한 상태를 준비하면서 결과적으로 Gameplay가 가능한 상태까지 이어지는 흐름으로 이해했습니다.

0.UserFacingExperience_RiteCombatGame%28LyraUserFacingExperienceDefinition%29.png

📸 Screenshot 1. UserFacingExperience_RiteCombatGame에서 DevMap과 B_Experience_RiteCombatGame이 연결된 설정.

1.B_Experience_RiteCombatGame%28LyraExperienceDefinition%29.png

📸 Screenshot 2. B_Experience_RiteCombatGame에서 기본 플레이어 구성으로 PawnData_RiteSeeker가 연결된 설정.

두 화면을 따로 연속해서 두는 게 길게 느껴진다면 최종 Notion에서는 UserFacingExperience → Experience 2분할 Composite 한 장으로 묶어도 좋습니다.


Experience에서 실제 Player 구성이 정해진다

RiteSeekers의 Editor 설정에서는 다음처럼 이어져 있습니다.

Text
UserFacingExperience_RiteCombatGame
→ B_Experience_RiteCombatGame
→ PawnData_RiteSeeker

UserFacingExperience_RiteCombatGame에서는 사용할 Map과 Experience를 연결하고, B_Experience_RiteCombatGame에서는 기본 PawnData를 정합니다.

처음에는 Experience가 게임 시작에 필요한 초기화를 전부 직접 처리하는 Object처럼 느껴졌습니다.

Source를 따라가 보니 실제 Ability와 Input 준비는 다른 시스템으로 이어졌습니다.

AbilitySet은 PlayerState와 ASC 쪽에서 Runtime 상태가 만들어지고, Player Input은 HeroComponent와 InputConfig를 거쳐 연결됩니다.

그래서 지금은 Experience를 이번 플레이에서 사용할 상위 Gameplay 구성을 정하는 위치에 가깝게 보고 있습니다.

Project Settings의 Asset Manager나 RiteCombatCore(GameFeatureData)처럼 그보다 앞의 설정은 B00에서 이미 따라갔기 때문에 여기서는 Experience 이후의 흐름만 이어서 봤습니다.


PawnData에는 Player에 필요한 설정이 모여 있었다

PawnData_RiteSeeker를 열어보면 Player를 구성하는 데 필요한 여러 데이터가 연결되어 있습니다.

Text
PawnClass
AbilitySets
TagRelationshipMapping
InputConfig
DefaultCameraMode

제가 이해한 역할은 다음 정도입니다.

Text
PawnClass
→ 어떤 Character를 사용할지
 
AbilitySets
→ 기본으로 어떤 Ability 구성을 줄지
 
TagRelationshipMapping
→ Ability Tag 사이의 관계
 
InputConfig
→ 어떤 Player Input을 사용할지
 
DefaultCameraMode
→ 기본 Camera

여기서 PawnData가 직접 모든 기능을 실행하는 것은 아니었습니다.

예를 들어 AbilitySet은 ASC 쪽에서 사용되고, InputConfig는 HeroComponent에서 실제 입력 Binding으로 이어집니다.

Text
PawnData
 
├─ PawnClass
│  → Pawn 구성
│
├─ AbilitySets
│  → PlayerState / ASC
│
├─ InputConfig
│  → HeroComponent
│
└─ DefaultCameraMode
   → Camera

하나의 PawnData에서 Player 구성을 한눈에 볼 수 있지만 실제 Runtime 처리는 각 시스템으로 나뉘어 있었습니다.

1.PawnData_RiteSeeker%28LyraPawnData%29.png

📸 Screenshot 3. PawnData_RiteSeeker에 PawnClass, AbilitySet, TagRelationshipMapping, InputConfig, DefaultCameraMode가 연결된 플레이어 구성.

이 Screenshot은 B02에서 가장 중요한 Editor Evidence라서 전체 Details를 보여주기보다 위 다섯 항목이 한눈에 읽히는 Crop이 좋습니다.


AbilitySet이 연결돼 있어도 아직 Runtime Ability는 아니다

PawnData에 AbilitySet Asset이 연결되어 있는 것과 현재 Player가 실제로 그 Ability를 가지고 있는 것은 달랐습니다.

Runtime에서는 AbilitySet이 ASC에 Grant되고 실제 AbilitySpec이 만들어져야 합니다.

Text
PawnData
→ AbilitySet
→ ASC Grant
→ AbilitySpec

Lyra의 Player 구조를 따라갈 때 여기서 PlayerState와 Pawn의 관계가 처음에는 조금 헷갈렸습니다.

현재 플레이어 흐름에서는 PlayerState가 ASC를 가지고 있고, Spawn된 Pawn은 그 ASC가 현재 사용하는 Avatar로 연결됩니다.

제가 이해한 기준은 이렇습니다.

Text
OwnerActor = PlayerState
→ Ability Runtime State를 가지고 있는 쪽
 
AvatarActor = Current Pawn
→ 현재 그 Ability를 실제로 사용하는 Character

그래서 PlayerState에 ASC가 이미 존재한다고 해서 현재 Pawn과의 연결까지 끝났다고 보지는 않았습니다.

Text
AbilitySet
→ ASC
→ AbilitySpec
→ Current Pawn

까지 실제 Runtime에서 이어져 있어야 현재 Character를 기준으로 Ability가 동작할 수 있습니다.


PawnExtension에서 Current Pawn의 준비 상태를 따라갔다

PlayerState에 ASC가 있다고 새 Pawn과의 연결이 자동으로 끝나는 것은 아니었습니다.

PawnData와 ASC가 지금 Spawn된 Pawn에 연결되는 과정이 필요했고, 여기서 PawnExtension을 따라가게 됐습니다.

제가 Source에서 이해한 역할은 크게 세 가지였습니다.

Text
PawnData
→ 현재 Pawn이 사용할 데이터
 
InitState
→ Pawn이 어느 준비 단계까지 왔는지
 
ASC
→ PlayerState의 ASC와 Current Pawn 연결

Lyra 계열 Source에서 Pawn의 InitState는 다음처럼 이어집니다.

Text
Spawned
→ DataAvailable
→ DataInitialized
→ GameplayReady

GameplayReady는 실제 InitState 이름입니다.

이 흐름을 보고 나서 Pawn이 World에 보인다는 사실과 Gameplay 준비가 끝났다는 사실을 따로 보게 됐습니다.

필요한 데이터와 Component가 준비되고 ASC와 현재 Pawn의 연결까지 이어진 뒤에야 마지막 상태로 넘어갑니다.

Text
Character Spawn
!=
Gameplay Ready

B02에서 가장 기억에 남았던 차이도 이 부분이었습니다.


InputConfig가 실제 Ability 입력으로 이어지는 과정

PawnData에는 InputData_RiteSeeker도 연결되어 있습니다.

InputConfig에서는 Player가 누르는 InputAction과 Gameplay에서 사용할 InputTag를 연결합니다.

InputTag 기반 Ability는 대표적으로 다음 흐름을 따라갑니다.

Text
InputAction
→ InputTag
→ HeroComponent
→ ASC AbilityInputTagPressed / Released
→ PlayerController PostProcessInput
→ ASC ProcessAbilityInput
→ Gameplay Ability Activation

InputConfig에 InputAction과 InputTag의 대응 관계가 있고, HeroComponent에서 실제 입력을 Binding합니다.

입력이 들어오면 ASC에 Pressed / Released 상태가 전달되고, PlayerController::PostProcessInput 이후 ProcessAbilityInput에서 현재 AbilitySpec과 Input 상태를 확인합니다.

그래서 InputAction이 들어왔다는 사실만으로 Ability가 실행됐다고 보지는 않았습니다.

현재 ASC에 기대한 AbilitySpec이 있어야 하고, InputTag도 연결되어 있어야 하며, Ability가 가진 Activation 조건도 통과해야 합니다.

GameplayEvent처럼 Player Input이 아닌 경로로 시작되는 Ability도 있기 때문에 ProcessAbilityInput은 모든 Ability의 공통 시작점이라기보다 InputTag 기반 Ability에서 따라간 대표 경로로 보고 있습니다.

5.InputData_RiteSeeker.png

📸 Screenshot 4. InputData_RiteSeeker에서 대표 Ability InputAction과 대응하는 InputTag가 연결된 설정.

이 화면도 InputData 전체를 길게 보여주기보다 실제 Ability InputAction 하나와 대응 Tag가 같이 보이는 부분만 Crop하는 게 좋습니다.


Source에서 다시 찾아간 위치

Experience부터 Input까지 다시 따라갈 때 주로 본 Source는 다음 정도였습니다.

Text
ULyraExperienceManagerComponent
→ Experience Load / Loaded
 
ALyraPlayerState
→ PawnData 설정
→ AbilitySet Grant
 
ULyraPawnExtensionComponent
→ PawnData / InitState
→ ASC와 Current Pawn 연결
 
ULyraHeroComponent
→ InputConfig 기반 Player Input 구성
 
ALyraPlayerController
→ PostProcessInput
→ ASC ProcessAbilityInput

처음에는 이 Class 이름들을 외워야 한다고 생각했습니다.

지금은 오히려 다음 순서를 기억하고 있는 편이 Source를 다시 찾기 쉬웠습니다.

Text
Experience
→ PawnData
→ ASC
→ Current Pawn
→ Input

어떤 상태를 확인하고 싶은지가 정해지면 그때 필요한 Class로 내려갈 수 있었습니다.


Pawn은 보이는데 Ability가 안 될 때

이 구조를 따라간 뒤에는 Pawn은 정상적으로 Spawn됐는데 Ability 입력이 되지 않는다는 상황도 조금 다르게 보였습니다.

예전에는 Input Mapping이나 GameplayAbility부터 확인했을 가능성이 큽니다.

지금은 먼저 이런 상태를 확인할 수 있습니다.

Text
올바른 PawnData가 들어왔는가
 
AbilitySet이 ASC에 Grant됐는가
 
Current Pawn이 ASC의 Avatar로 연결됐는가
 
InputConfig가 실제로 Binding됐는가

예를 들어 ASC에 기대한 AbilitySpec까지 이미 존재한다면 Pawn Spawn이나 Ability Grant를 다시 볼 이유가 적습니다.

그때는 InputTag와 Activation 쪽으로 내려가면 됩니다.

반대로 AbilitySpec 자체가 없다면 ProcessAbilityInput부터 확인하는 것도 너무 뒤입니다.

이렇게 나눠서 보기 시작하면서 BeginPlay가 호출됐으니 초기화는 끝났겠지라고 생각하는 일이 줄었습니다.

AbilitySpec 이후 Input과 Activation을 확인하는 과정은 B06에서 실제 Runtime 값을 기준으로 다시 정리했습니다.


Editor 설정과 Source에서 확인한 범위

현재 Editor에서는 다음 연결을 확인했습니다.

Text
UserFacingExperience_RiteCombatGame
→ B_Experience_RiteCombatGame
→ PawnData_RiteSeeker

PawnData_RiteSeeker에는 다음 설정이 연결되어 있습니다.

Text
PawnClass
AbilitySets
TagRelationshipMapping
InputConfig
DefaultCameraMode

Source에서는 Experience Manager, PlayerState, PawnExtension, HeroComponent가 각각 다음 상태를 준비하는 위치도 따라갔습니다.

다만 앞에서 그린 전체 흐름을 하나의 정확한 비동기 Call Stack이라고 설명하지는 않습니다.

각 시스템이 실제 Runtime에서 어느 Frame과 어느 시점에 준비되는지, Owner / Avatar 전환이 정확히 언제 일어나는지까지 말하려면 해당 시점에 Debugger를 걸고 따로 확인해야 합니다.

B02에서는 Editor 설정과 Source에서 직접 확인한 연결까지만 기준으로 잡았습니다.


프로젝트를 진행하며 달라진 부분

처음에는 Pawn이 Spawn되고 Input이 들어오면 Gameplay 초기화도 거의 끝났다고 생각했습니다.

지금은 그 사이의 상태를 조금 더 나눠서 봅니다.

Text
Experience
→ 플레이 구성 선택
 
PawnData
→ Player 구성 데이터 제공
 
PlayerState / ASC
→ Ability Runtime State 관리
 
PawnExtension
→ Current Pawn과 ASC 연결
 
HeroComponent / InputConfig
→ Player Input 구성
 
PlayerController / ASC
→ Ability Input 처리

특정 Class 하나가 모든 초기화를 담당하는 것이 아니라 여러 시스템이 필요한 상태를 이어받으면서 GameplayReady까지 진행되는 구조였습니다.

이 흐름을 이해한 뒤에는 Job / Class Ability나 Equipment, Combat을 볼 때도 마지막 기능이 정상인지부터 보기보다 그 기능이 실행되기 전에 어떤 Runtime 연결이 먼저 필요한지 같이 보게 됐습니다.


정리

RiteSeekers에서 Experience부터 GameplayReady까지 따라가면서 가장 크게 달라진 것은 Pawn이 Spawn된 것과 플레이 준비가 끝난 것을 같은 상태로 보지 않게 된 점이었습니다.

제가 따라간 흐름은 다음과 같습니다.

Text
Experience
→ PawnData
→ AbilitySet / ASC
→ PawnExtension
→ Current Pawn 연결
→ InputConfig Binding
→ ASC Input Processing
→ GameplayReady

처음에는 이 과정을 하나의 초기화 함수처럼 생각했습니다.

Source와 Editor 설정을 같이 보면서 Experience에서 Player 구성을 정한 뒤 PawnData, PlayerState, PawnExtension, HeroComponent가 각각 필요한 상태를 이어받는 구조라는 것을 이해하게 됐습니다.

그 이후에는 Pawn은 정상적으로 보이는데 Ability가 동작하지 않는다는 상황도 하나의 초기화 문제로 묶기보다, Spawn 뒤에 어떤 연결까지 실제로 준비됐는지 순서대로 확인할 수 있게 됐습니다.

빠른 검색

프로젝트, Evidence, 디버깅 노트, 학습 기록을 검색합니다.

목차