UE5 핵심 개념 정리: UObject·GAS·렌더링·애니메이션

Kyu_·2026년 8월 6일

37주차

목록 보기
3/3

CS

개념

TObjectPtr과 TWeakObjectPtr, TSoftObjectPtr

TObjectPtr : 이미 존재하는 UObject를 강하게 참조한다. GC가 이 참조를 인식하므로, 이 참조가 살아있는동안 대상 UObject를 수집하지 않음
TWeakObjectPtr : 이미 존재하는 UObject를 소유하지않고 관찰만 함, GC가 대상을 수집할수 있으므로 사용전 IsValid() 확인이 필요
TSoftObjectPtr : 에셋을 직접 들고있지 않고 에셋 경로만 들고 있다가 필요할때 로드하는 포인터. 비동기 로드도 사용

TSubclassOf와 일반 UClass*의 차이

TSubclassOf는 객체가 아니라 클래스 자체를 저장할때 쓰고, 그 클래스가 반드시 T를 상속받도록 제한하는 타입

UPROPERTY(EditAnywhere)
TSubclassOf<AActor> ProjectileClass;

GetWorld()->SpawnActor<AActor>(ProjectileClass);

UClass*는 아무 클래스나 들어갈 수 있지만, TSubclassOf는 AActor 계열만 들어가도록 타입 검사를 해준다. UClass*의 래퍼라고 보면 된다.

UClass* ProjectilesClass;

언리얼 Interface와 상속의 차이점

인터페이스는 이 기능을 제공한다는 약속만 정의, 서로 상속 관계가 없는 클래스들이 같은 기능을 구현하게 할 때 사용(상호작용 시스템)
상속은 공통 데이터/기본 구현을 물려받는 관계, 인터페이스는 공통 기능의 규약만 맞추는 관계라고 보면 됨

Cast<>()는 언제 사용하고, 실패하면 무엇을 반환할까?

Cast()는 UObject계열을 원하는 하위타입으로 안전하게 캐스팅할 때 사용함
실패하면 nullptr을 반환한다

UObejct포인터를 검사할 때 nullptr 비교만 하지않고 IsValid()를 쓰는 이유

nullptr 비교는 주소값이 비어있는지만 확인
IsValid()는 nullptr이 아닌지뿐 아니라, UObject가 이미 삭제 예약(Pending Kill)되었거나 GC 대상이 된 상태는 아닌지도 확인한다.
즉 주소가 남아있어도 더 이상 안전하게 쓰면 안되는 UObject를 걸러준다.

CreateDefaultSubobject와 NewObject는 각각 언제 사용하는가?

CreateDefaultSubobject : 액터나 UObject의 생성자 안에서, 그 클래스가 기본적으로 항상 가져야 하는 컴포넌트를 만들때 사용한다. ex) 캐릭터가 생성될 때마다 기본으로 카메라 컴포넌트를 가지게 된다.
NewObject : 게임 실행중에 필요할때 UObject나 컴포넌트를 동적으로 생성할때 쓴다.

UInventory* Inventory = NewObject<UInventory>(this);

참고로 월드에 존재하는 액터를 만들 때는 NewObject가 아니라 SpawnActor를 쓴다.

OnComponentBeginOverlap과 OnComponentHit의 차이

OnComponentBeginOverlap : 두 컴포넌트의 Collision Response가 Overlap일때 서로 겹치기 시작하면 호출된다.
OnComponentHit은 컴포넌트가 다른 물체와 Block 충돌했을때 호출된다.

Block : 서로 통과하지 못하고 물리적으로 막힘
Overlap : 서로 통과하지만 겹치기 시작/끝나는 이벤트 받을 수 있음
Ignore : 충돌 자체를 무시해서 막히지도 않고 오버랩 이벤트도 없음

Object Channel, Trace Channel은 충돌검사할때 붙이는 이름표라고 생각하면 된다. Object Channel은 물체가 자기가자신에게 붙이는 이름표, Trace Channel은 트레이스가 자기자신한테 붙이는 이름표
보통 Object Channel은 물체끼리 충돌, 오버랩할때 어떤 물체인지 구분하는 기준이고, Trace Channel은 라인 트레이스를 쐈을때 대상이 그 트레이스를 Ignore/Block할 기준

Collision Enabled

NoCollision : 충돌 자체에 참여하지 않음
QueryOnly : 트레이스/오버랩 같은 검사에는 반응, 물리적으로 밀리거나 튕기지 않음 ex) 아이템 줍기, 공격 판정 범위
PhysicsOnly : 물리 시뮬레이션에는 반응하지만, 트레이스/오버랩 검사 대상은 아님 ex) 물리적으로 떨어지고 부딪히기만 하는 물체
QueryAndPhysics : 검사와 물리 시뮬레이션 둘 다 한다. ex) 물리상자, 총알 트레이스에도 맞고, 바닥에도 떨어짐

월드좌표와 로컬좌표의 차이

월드좌표는 월드 원점(0, 0, 0) 기준의 절대 위치
상대좌표는 부모 컴포넌트 기준의 상대 위치, 무기같은것들에 사용

SetActorLocation은 액터를 지정한 월드좌표로 이동시키는것이지만, AddActorLocalOffset은 액터가 바라보는 방향을 기준으로 이동량을 더함

FTransform

FVector : 3차원 값, 위치/방향/크기등을 표현할 수 있음
FRotator : Pitch/Yaw/Roll로 표현한 회전값
FTransform : 위치(Translation)/회전(Rotation)/크기(Scale)를 한 번에 가진 구조체

이동 방향 벡터를 정규화하지 않으면 어떤 문제가 생길 수 있는가

앞 이동 방향이 (1, 0)이면 길이가 1이다. 근데 앞+오른쪽 방향이 (1, 1)이면 길이가 1.41이다. 둘다 같은 속도 값을 곱하면 대각선으로 이동할때 1.4배가 빨라진다.
방향벡터를 길이1로 정규화해서 어느방향이든 같은 속도로 움직이게 해야한다 (0.707, 0.707)이런식으로

UDataAsset과 DataTable은 각각 언제사용하는게 좋은가

DataTable은 기획자가 쉽게 수치를 변경할 수 있으므로 수치값등에 사용
UDataAsset은 하나의 논리적인 설정 묶음을 에셋 하나로 만들때 사용한다.

GameplayTag는 왜 사용하고, 일반 FName이나 문자열과 어떤 차이가 있는가?

GameplayTag는 GAS에서 어빌리티/이펙트 조건을 식별할때 많이 사용한다.
차이점은 계층 구조와 태그 전용기능이 있다. 태그는 우선 계층구조로 이루어져 있음, 또 태그 목록을 프로젝트에서 미리등록하므로 에디터에서 등록도 편하고, 오타방지 및 미리 검사할 수 있다는 장점이 있다.

Gameplay Ability, Gameplay Effect, AttributeSet은 각각 어떤 역할을 하는가?

Gameplay Ability : 행동의 흐름
Gameplay Effect : 능력으로 인해 적용되는 결과
만약에 파이어볼을 날린다면
GA : 파이어볼, 입력을 받고, 쿨다운/마나를 확인하고, 애니메이션을 재생하고, 투사체를 생성한다.
GE : 맞은 대상의 체력을 30깎는다, 5초동안 매초 체력을 2씩 깎고 State.Burning 태그를 준다.

GA는 입력받기/조준하기/투사체 생성하기/애니메이션 재생하기 같은 행동흐름을 만들 수 있다.
GE는 수치/태그/버프/디버프를 데이터 기반으로 적용하는 용도

AttributeSet은 체력/최대체력/공격력/이동속도 같은 실제 속성값을 보관하고 변경을 처리한다.

AbilitySystemComponent

AbilitySystemComponent는 GAs의 중심 컴포넌트이다. GA를 부여/활성화, GE를 적용/제거, Tag와 AttributeSet을 관리한다.
네트워크 복제와 클라이언트 예측도 ASC가 담당한다.

GAS에서 Owner Actor와 Avatar Actor

Owner Actor : ASC를 소유하는 지속적인 주체, ex) PlayerState
Avatar Actor : 현재 월드에서 움직이고 능력을 쓰는 Pawn/Character, ex) 플레이어 캐릭터
Target Actor : 공격이나 Effect를 받는 대상 ex) 몬스터

단순 싱글 플레이 캐릭터에서는 Onwer와 Avatar가 둘다 캐릭터일 수 있다. 멀티플레이에서 리스폰해도 능력/스텟을 유지하려면 Owner를 PlayerState에 두고, 새로 스폰된 Character를 Avatar로 연결할 수 있다.

언리얼 Subsystem은 무엇인가

Subsystem은 기능을 별도 객체로 분리해서 결합도를 낮추는 구조. GameInstanceSubsystem이라고 하면 게임 인스턴스에 모든 기능을 몰아넣지 않고, 매치메이킹/세이브로드/에셋 로딩관리 같은 기능을 각각 Subsystem으로 나눌 수 있다.

C++클래스와 블루프린트는 각각 어떤 역할로 나누어 사용하는게 좋은가?

C++ : 성능이 중요한 반복 로직, 복잡한 시스템, 기반 기능
블루프린트 : UI연결, 애니메이션 이벤트, 이펙트/사운드 설정, 간단한 게임 연출, 기획 수치 조정

블루프린트는 노드가 언리얼의 VM을 거쳐 실행돼서 같은 일을 C++ 네이티브 코드로 돌리는것보다 비용이 더 든다.

UENUM과 USTRUCT

UENUM은 상태를 이름있는 값으로 구분하고, 언리얼 리플렉션에 등록하면 블루프린트나 에디터 드롭다운에서도 쓸 수 있다.
USTRUCT는 UObject처럼 월드에 독립적으로 존재할 필요는 없고, 아이템 정보/스탯처럼 관련 값들을 묶는 데이터 타입으로 사용한다.

CDO

Class Default Object, 클래스별 기본값 템플릿 객체
흐름은

  1. 언리얼이 AEnemy 클래스를 처음 준비할때 AEnemy의 CDO를 만든다.
  2. CDO를 만들면서 C++ 생성자가 실행된다. 기본값, 기본 컴포넌트가 여기서 정해짐
  3. 블루프린트 자식 클래스라면 에디터에서 설정한 값도 그 블루프린트 클래스의 CDO에 저장된다.
  4. 나중에 AEnemy 인스턴스를 Spawn하면, 그 인스턴스는 해당 클래스 CDO의 기본값을 바탕으로 초기화한다.

CDO를 쓰는이유는 클래스의 기본 상태를 한곳에서 저장하고, 모든 인스턴스를 일관되게 초기화하기 위해서다.

UWorld와 Level

UWorld는 현재 실행중인 하나의 게임 세계 전체를 관리함
레벨은 월드를 구성하는 맵 데이터/액터 묶음
예시
UWorld : 현재 플레이중인 오픈월드 전체
Persistent Level : 항상 로드된 기본 지형과 액터
Sub Level : 마을, 던전, 건물 내부처럼 필요할 때 로드/해제하는 구역

Persistent Level과 Sub Level

Persistent Level은 UWorld가 유지되는 동안 항상 로드되어 있는 기준 레벨
Sub Level은 Persistent Level에 붙는 부분 맵, 필요할때 로드하고, 멀어지면 해제할 수 있다. 하나의 PersistentLevel에 여러 SubLevel이 붙을 수 있다.

  • Persistent Level: 하늘, 전역 환경, 기본 지형
  • Sub Level: 마을 A, 던전 B, 건물 내부

플레이어가 마을 A 근처에 가면 Sub Level을 로드하고, 멀어지면 언로드해서 메모리와 로딩 비용을 아낀다.

EditAnywhere, VisibleAnywhere

EditAnywhere : 에디터의 디테일 패널에서 값을 볼수도있고 수정도 가능
VisibleAnywhere : 에디터의 디테일 패널에서 볼 수만 있고 수정은 불가
블루프린트 그래프에서 접근 가능한건 BlueprintReadOnly, BlueprintReadWrite가 담당

Build.cs의 역할

모듈을 어떻게 컴파일할지 설정하는 파일이고 Unreal Build Tool이 읽는다.

  • 모듈이 의존하는 다른모듈(UMG, Engine, Core등)
  • 외부 라이브러리와 헤더 경로
  • 컴파일 옵션이나 전처리기 정의

Behavior Tree와 Black Board의 차이

BT는 조건에 따라 어떤 행동을 실행할지 정한 AI 의사결정 트리이고 BB는 BT가 판단할때 쓰는 데이터를 저장하는 공간

NavMesh는 AI가 이동 가능한 바닥 영역을 엔진이 분석해서 만든 길찾기 데이터
MoveTo는 NavMesh를 보고 출발지에서 목표까지 갈 경로를 계산해서 벽이나 장애물을 피해 움직인다.
NavMesh가 없거나, 목적지가 NavMesh밖이면 경로를 찾지 못해서 실패할 수 있다.

Event Graph와 Anim Graph

Event Graph : 캐릭터 속도, 공중여부, 조준여부처럼 애니메이션 판단에 필요한 변수를 매 프레임 갱신하는 곳
Anim Graph : 그 변수들을 이용해서 Idle/Run 상태 전환, Blend, 레이어 적용등을 거쳐 최종 포즈를 만드는 곳

애니메이션 몽타주는 무엇이고, 상태 머신 애니메이션과 언제 구분해서 쓰는가

애니메이션 몽타주는 필요한 순간에 재생하는 단발성 애니메이션
상태 머신 애니메이션은 Idle/Walk/Run/Jump처럼 계속 이어지는 기본 이동 상태를 관리하는데 적합

TArray과 std::vector

둘은 연속메모리 기반 동적 배열이라 인덱스 접근과 순회가 빠르고 캐시효율이 좋다.
TArray를 언리얼에서 많이쓰는이유는 UCLASS, USTRUCT안에서 UPROPERTY등록을 했을때 언리얼 리플렉션/복제/직렬화/블루프린트와 연동할 수 있다. std::vector는 등록이 안됨

InputAction과 IMC

InputAction은 행동자체를 정의, IA_Jump, IA_Move, IA_Attacke등
Input Mapping Context는 어떤 키/패드를 어떤 IA에 연결할지 정의

리플렉션 시스템

실행중인 언리얼이 클래스/변수/함수의 정보와 설정을 알 수 있게 만드는 시스템
흐름

  1. 헤더에 UCLASS, USTRUCT, UENUM, UPROPERTY, UFUNCTION을 쓴다
  2. 빌드전에 UHT(Unreal Header Tool)가 헤더를 읽는다 -> UHT는 이 매크로가 붙은 클래스, 변수, 함수의 이름/타입/옵션을 분석한다.
  3. UHT가 .generated.h, .gen.cpp 같은 자동 생성 코드를 만든다 -> GENERATED_BODY()는 이 자동생성 코드와 우리가 작성한 클래스와 연결되는 자리다.
  4. 컴파일 후 실행 중에는 언리얼이 UClass, FProperty(UPROPERTY로 등록한 변수 하나를 표현하는 메타데이터 객체), UFunction, UEnum같은 메타데이터를 통해 그 정보를 읽을 수 있다. -> UHT는 정보를 등록해서 에디터 Details패널 노출, 블루프린트 접근 같은 기능을 붙일 수 있게됨

UObject의 Outer는 무엇이고 왜 필요한가?

Outer는 UObject를 만들때 지정하는 소속 객체

UInventoryItem* Item = NewObject<UInventoryItem>(PlayerCharacter);

PlayerCharacter가 Item의 Outer이다.
이 아이템 객체는 PlayerCharacter에 소속되어 있다는 관계를 엔진에 알려주는것

  • 객체의 소속/이름 경로 구성
  • 어떤 월드나 패키지에 속하는지 찾기
  • 객체가 어느 생명주기/컨텍스트에 묶이는지 판단

쿠킹과 패키징

Cooking : 에디터용 원본 에셋을 목표 플랫폼에서 실행 가능한 데이터로 변환하는 과정
Packaging : 빌드된 실행 파일, DLL, Cook된 에셋, 설정파일등을 모아서 유저가 에디터없이 실행할 수 있는 배포 폴더를 만드는 과정

.exe와 .dll은 컴파일때 생기고
Cooking은 .umap, .uasset을 해당 플랫폼이 실행할 수 있는 형태로 변경
패키징은 이들을 합쳐서 배포가능한 형태로 만듬 이때 .pak설정을 했다면 .pak이 생기고, 최신버전에서 IoStore를 쓰는 프로젝트는 .utoc, .ucas가 생길 수 있다.

USaveGame

USaveGame은 저장할 데이터를 담아 디스크의 저장 슬롯에 쓰고, 나중에 다시 읽기 위한 데이터 객체. 게임을 껐다 켜도 저장파일은 남음

UPrimaryDataAsset이랑 UDataAsset의 차이점

PrimaryAssetId로 식별되는지 안되는지 차이, 특히 AssetManager가 관리/로드할 수 있는 데이터에셋이 PrimaryDataAsset이고, UDataAsset은 일반적인 데이터에셋

AnimNotify와 AnimNotifyState

AnimNotify는 애니메이션의 한 시점에 한 번 실행되는 알림
AnimNotifyState는 애니메이션의 일정 구간동안 유지되는 알림

Root Motion과 In-Place

RootMotion은 애니메이션 안의 Root Bone 이동량을 읽어서, 캐릭터의 실제 위치와 회전도 같이 이동시킴
In-place는 Root Bone은 제자리에 있고, 걷는 모션만 재생, 실제 캐릭터 이동은 코드가 처리

0개의 댓글