티스토리 뷰
🟩 오늘의 목표
- 언리얼 리플렉션 시스템의 메커니즘과 UCLASS, UPROPERTY, UFUNCTION 매크로의 필요성을 명확히 이해한다.
- 게임 프레임워크를 구성하는 주요 클래스들의 역할과 네트워크상의 존재 위치를 명확히 구분한다.
- 액터의 생명주기 흐름과 CDO(Class Default Object)의 초기화 원리를 습득하여 안정적인 초기화 로직을 설계한다.
🟧 1. 언리얼 리플렉션과 클래스 시스템
🟦 리플렉션(Reflection) 및 UCLASS 정의
- UCLASS 매크로는 클래스를 리플렉션 시스템에 등록하여 엔진이 타입 정보, 가비지 컬렉션(GC), 직렬화 등을 관리할 수 있게 하는 필수 장치이다.
- 언리얼은 C++ 표준 기능만으로는 에디터 연동, 네트워크 복제, 직렬화에 필요한 정보를 일관되게 처리하기 어렵기 때문에 리플렉션 시스템이 반드시 필요하다.
- 에디터 노출이나 데이터 저장이 필요한 멤버는 UPROPERTY 매크로를 사용하며, 블루프린트 호출이나 이벤트 바인딩이 필요한 함수는 UFUNCTION 매크로를 사용하여 엔진에 정보를 명시하다.
- 리플렉션에 등록된 클래스는 보통 AActor나 UActorComponent와 같은 UObject 계열이다.
🟧 2. 게임 프레임워크 핵심 클래스 구조
🟦 게임 규칙 및 전역 컨텍스트 클래스
- AGameModeBase는 게임 규칙의 권위자(Authority)로서 서버에만 존재하며, 스폰 규칙이나 승패 판정 로직의 중심 역할을 수행한다.
- UGameInstance는 게임 프로세스 전체에 1개만 존재하는 전역 컨텍스트로, 레벨 전환 시에도 데이터가 유지되며 프로세스 단위의 전역 상태를 관리한다.
- UGameInstanceSubsystem은 전역 서비스를 모듈화하여 관리하기에 최적화된 구조로, 책임 분리(세션, 저장, 로깅 등)에 매우 유리하다.
🟦 네트워크 상태 공유 및 제어 클래스
- AGameState는 현재 매치의 공유 상태(남은 시간, 팀 점수 등)를 담아 모든 클라이언트에 복제(Replicate)하는 역할을 한다.
- APlayerState는 플레이어 1명의 공유 정보(닉네임, 점수 등)를 관리하며, 한 플레이어의 정보가 다른 모든 클라이언트에서도 보일 수 있도록 복제된다.
- APlayerController는 플레이어의 입력을 처리하고 APawn을 조종(Possess)하는 주체이며, 서버와 소유 중인 클라이언트에만 존재한다.
🟧 3. 액터의 생명주기와 초기화 원리
🟦 액터 수명 주기 흐름 (BeginPlay / EndPlay)
- BeginPlay는 액터가 월드에서 실제로 플레이를 시작할 때 호출되며, 월드 접근이나 런타임 데이터 기반 초기화 로직을 작성하기에 적합하다.
- EndPlay는 액터가 제거되거나 플레이가 끝날 때 호출되어 자원 정리 및 델리게이트 언바인딩 등 수명 정리를 담당한다.
- C++ 소멸자(~Class)는 가비지 컬렉션 모델상 호출 타이밍이 불분명하므로, 정리는 반드시 엔진에서 제공하는 EndPlay 훅을 사용해야 한다.
🟦 생성자와 CDO(Class Default Object)
- 생성자(Constructor)는 CDO 생성 단계에서 호출되며 컴포넌트 생성(CreateDefaultSubobject) 및 클래스 기본값 설정에 집중해야 한다.
- CDO는 각 UCLASS마다 하나씩 존재하는 클래스 기본 인스턴스로, 이후 생성되는 모든 인스턴스의 초기화 기준이 되는 템플릿 역할을 한다.
- 생성자는 CDO 생성 단계에서도 호출되므로 월드가 없는 시점임을 고려하여 안정적으로 작동하도록 설계해야 다.
🟧 핵심 요약 및 주의사항
- 서버 권한 확인: AGameModeBase는 클라이언트에서 항상 null을 반환하므로 클라이언트 로직을 여기에 포함하면 안 된다.
- 데이터 위치 선정: 모든 플레이어가 공유해야 하는 정보는 UGameInstance가 아닌 AGameState나 APlayerState에 두어야 정상적으로 복제된다.
- 무효 참조 방지: 레벨 전환 시 사라지는 액터 참조는 TWeakObjectPtr를 사용하여 댕글링 포인터 문제를 방지하는 것이 안전하다.
- CDO 논리 충돌: 생성자 내부에 월드 존재를 가정한 로직을 넣으면 CDO 생성 단계에서 엔진 초기화 충돌이 발생할 수 있으니 주의해야 한다.