TObjectPtr : 이미 존재하는 UObject를 강하게 참조한다. GC가 이 참조를 인식하므로, 이 참조가 살아있는동안 대상 UObject를 수집하지 않음
TWeakObjectPtr : 이미 존재하는 UObject를 소유하지않고 관찰만 함, GC가 대상을 수집할수 있으므로 사용전 IsValid() 확인이 필요
TSoftObjectPtr : 에셋을 직접 들고있지 않고 에셋 경로만 들고 있다가 필요할때 로드하는 포인터. 비동기 로드도 사용
TSubclassOf는 객체가 아니라 클래스 자체를 저장할때 쓰고, 그 클래스가 반드시 T를 상속받도록 제한하는 타입
UPROPERTY(EditAnywhere)
TSubclassOf<AActor> ProjectileClass;
GetWorld()->SpawnActor<AActor>(ProjectileClass);
UClass*는 아무 클래스나 들어갈 수 있지만, TSubclassOf는 AActor 계열만 들어가도록 타입 검사를 해준다. UClass*의 래퍼라고 보면 된다.
UClass* ProjectilesClass;
인터페이스는 이 기능을 제공한다는 약속만 정의, 서로 상속 관계가 없는 클래스들이 같은 기능을 구현하게 할 때 사용(상호작용 시스템)
상속은 공통 데이터/기본 구현을 물려받는 관계, 인터페이스는 공통 기능의 규약만 맞추는 관계라고 보면 됨
Cast()는 UObject계열을 원하는 하위타입으로 안전하게 캐스팅할 때 사용함
실패하면 nullptr을 반환한다
nullptr 비교는 주소값이 비어있는지만 확인
IsValid()는 nullptr이 아닌지뿐 아니라, UObject가 이미 삭제 예약(Pending Kill)되었거나 GC 대상이 된 상태는 아닌지도 확인한다.
즉 주소가 남아있어도 더 이상 안전하게 쓰면 안되는 UObject를 걸러준다.
CreateDefaultSubobject : 액터나 UObject의 생성자 안에서, 그 클래스가 기본적으로 항상 가져야 하는 컴포넌트를 만들때 사용한다. ex) 캐릭터가 생성될 때마다 기본으로 카메라 컴포넌트를 가지게 된다.
NewObject : 게임 실행중에 필요할때 UObject나 컴포넌트를 동적으로 생성할때 쓴다.
UInventory* Inventory = NewObject<UInventory>(this);
참고로 월드에 존재하는 액터를 만들 때는 NewObject가 아니라 SpawnActor를 쓴다.
OnComponentBeginOverlap : 두 컴포넌트의 Collision Response가 Overlap일때 서로 겹치기 시작하면 호출된다.
OnComponentHit은 컴포넌트가 다른 물체와 Block 충돌했을때 호출된다.
Block : 서로 통과하지 못하고 물리적으로 막힘
Overlap : 서로 통과하지만 겹치기 시작/끝나는 이벤트 받을 수 있음
Ignore : 충돌 자체를 무시해서 막히지도 않고 오버랩 이벤트도 없음
Object Channel, Trace Channel은 충돌검사할때 붙이는 이름표라고 생각하면 된다. Object Channel은 물체가 자기가자신에게 붙이는 이름표, Trace Channel은 트레이스가 자기자신한테 붙이는 이름표
보통 Object Channel은 물체끼리 충돌, 오버랩할때 어떤 물체인지 구분하는 기준이고, Trace Channel은 라인 트레이스를 쐈을때 대상이 그 트레이스를 Ignore/Block할 기준
NoCollision : 충돌 자체에 참여하지 않음
QueryOnly : 트레이스/오버랩 같은 검사에는 반응, 물리적으로 밀리거나 튕기지 않음 ex) 아이템 줍기, 공격 판정 범위
PhysicsOnly : 물리 시뮬레이션에는 반응하지만, 트레이스/오버랩 검사 대상은 아님 ex) 물리적으로 떨어지고 부딪히기만 하는 물체
QueryAndPhysics : 검사와 물리 시뮬레이션 둘 다 한다. ex) 물리상자, 총알 트레이스에도 맞고, 바닥에도 떨어짐
월드좌표는 월드 원점(0, 0, 0) 기준의 절대 위치
상대좌표는 부모 컴포넌트 기준의 상대 위치, 무기같은것들에 사용
SetActorLocation은 액터를 지정한 월드좌표로 이동시키는것이지만, AddActorLocalOffset은 액터가 바라보는 방향을 기준으로 이동량을 더함
FVector : 3차원 값, 위치/방향/크기등을 표현할 수 있음
FRotator : Pitch/Yaw/Roll로 표현한 회전값
FTransform : 위치(Translation)/회전(Rotation)/크기(Scale)를 한 번에 가진 구조체
앞 이동 방향이 (1, 0)이면 길이가 1이다. 근데 앞+오른쪽 방향이 (1, 1)이면 길이가 1.41이다. 둘다 같은 속도 값을 곱하면 대각선으로 이동할때 1.4배가 빨라진다.
방향벡터를 길이1로 정규화해서 어느방향이든 같은 속도로 움직이게 해야한다 (0.707, 0.707)이런식으로
DataTable은 기획자가 쉽게 수치를 변경할 수 있으므로 수치값등에 사용
UDataAsset은 하나의 논리적인 설정 묶음을 에셋 하나로 만들때 사용한다.
GameplayTag는 GAS에서 어빌리티/이펙트 조건을 식별할때 많이 사용한다.
차이점은 계층 구조와 태그 전용기능이 있다. 태그는 우선 계층구조로 이루어져 있음, 또 태그 목록을 프로젝트에서 미리등록하므로 에디터에서 등록도 편하고, 오타방지 및 미리 검사할 수 있다는 장점이 있다.
Gameplay Ability : 행동의 흐름
Gameplay Effect : 능력으로 인해 적용되는 결과
만약에 파이어볼을 날린다면
GA : 파이어볼, 입력을 받고, 쿨다운/마나를 확인하고, 애니메이션을 재생하고, 투사체를 생성한다.
GE : 맞은 대상의 체력을 30깎는다, 5초동안 매초 체력을 2씩 깎고 State.Burning 태그를 준다.
GA는 입력받기/조준하기/투사체 생성하기/애니메이션 재생하기 같은 행동흐름을 만들 수 있다.
GE는 수치/태그/버프/디버프를 데이터 기반으로 적용하는 용도
AttributeSet은 체력/최대체력/공격력/이동속도 같은 실제 속성값을 보관하고 변경을 처리한다.
AbilitySystemComponent는 GAs의 중심 컴포넌트이다. GA를 부여/활성화, GE를 적용/제거, Tag와 AttributeSet을 관리한다.
네트워크 복제와 클라이언트 예측도 ASC가 담당한다.
Owner Actor : ASC를 소유하는 지속적인 주체, ex) PlayerState
Avatar Actor : 현재 월드에서 움직이고 능력을 쓰는 Pawn/Character, ex) 플레이어 캐릭터
Target Actor : 공격이나 Effect를 받는 대상 ex) 몬스터
단순 싱글 플레이 캐릭터에서는 Onwer와 Avatar가 둘다 캐릭터일 수 있다. 멀티플레이에서 리스폰해도 능력/스텟을 유지하려면 Owner를 PlayerState에 두고, 새로 스폰된 Character를 Avatar로 연결할 수 있다.
Subsystem은 기능을 별도 객체로 분리해서 결합도를 낮추는 구조. GameInstanceSubsystem이라고 하면 게임 인스턴스에 모든 기능을 몰아넣지 않고, 매치메이킹/세이브로드/에셋 로딩관리 같은 기능을 각각 Subsystem으로 나눌 수 있다.
C++ : 성능이 중요한 반복 로직, 복잡한 시스템, 기반 기능
블루프린트 : UI연결, 애니메이션 이벤트, 이펙트/사운드 설정, 간단한 게임 연출, 기획 수치 조정
블루프린트는 노드가 언리얼의 VM을 거쳐 실행돼서 같은 일을 C++ 네이티브 코드로 돌리는것보다 비용이 더 든다.
UENUM은 상태를 이름있는 값으로 구분하고, 언리얼 리플렉션에 등록하면 블루프린트나 에디터 드롭다운에서도 쓸 수 있다.
USTRUCT는 UObject처럼 월드에 독립적으로 존재할 필요는 없고, 아이템 정보/스탯처럼 관련 값들을 묶는 데이터 타입으로 사용한다.
Class Default Object, 클래스별 기본값 템플릿 객체
흐름은
CDO를 쓰는이유는 클래스의 기본 상태를 한곳에서 저장하고, 모든 인스턴스를 일관되게 초기화하기 위해서다.
UWorld는 현재 실행중인 하나의 게임 세계 전체를 관리함
레벨은 월드를 구성하는 맵 데이터/액터 묶음
예시
UWorld : 현재 플레이중인 오픈월드 전체
Persistent Level : 항상 로드된 기본 지형과 액터
Sub Level : 마을, 던전, 건물 내부처럼 필요할 때 로드/해제하는 구역
Persistent Level은 UWorld가 유지되는 동안 항상 로드되어 있는 기준 레벨
Sub Level은 Persistent Level에 붙는 부분 맵, 필요할때 로드하고, 멀어지면 해제할 수 있다. 하나의 PersistentLevel에 여러 SubLevel이 붙을 수 있다.
플레이어가 마을 A 근처에 가면 Sub Level을 로드하고, 멀어지면 언로드해서 메모리와 로딩 비용을 아낀다.
EditAnywhere : 에디터의 디테일 패널에서 값을 볼수도있고 수정도 가능
VisibleAnywhere : 에디터의 디테일 패널에서 볼 수만 있고 수정은 불가
블루프린트 그래프에서 접근 가능한건 BlueprintReadOnly, BlueprintReadWrite가 담당
모듈을 어떻게 컴파일할지 설정하는 파일이고 Unreal Build Tool이 읽는다.
BT는 조건에 따라 어떤 행동을 실행할지 정한 AI 의사결정 트리이고 BB는 BT가 판단할때 쓰는 데이터를 저장하는 공간
NavMesh는 AI가 이동 가능한 바닥 영역을 엔진이 분석해서 만든 길찾기 데이터
MoveTo는 NavMesh를 보고 출발지에서 목표까지 갈 경로를 계산해서 벽이나 장애물을 피해 움직인다.
NavMesh가 없거나, 목적지가 NavMesh밖이면 경로를 찾지 못해서 실패할 수 있다.
Event Graph : 캐릭터 속도, 공중여부, 조준여부처럼 애니메이션 판단에 필요한 변수를 매 프레임 갱신하는 곳
Anim Graph : 그 변수들을 이용해서 Idle/Run 상태 전환, Blend, 레이어 적용등을 거쳐 최종 포즈를 만드는 곳
애니메이션 몽타주는 필요한 순간에 재생하는 단발성 애니메이션
상태 머신 애니메이션은 Idle/Walk/Run/Jump처럼 계속 이어지는 기본 이동 상태를 관리하는데 적합
둘은 연속메모리 기반 동적 배열이라 인덱스 접근과 순회가 빠르고 캐시효율이 좋다.
TArray를 언리얼에서 많이쓰는이유는 UCLASS, USTRUCT안에서 UPROPERTY등록을 했을때 언리얼 리플렉션/복제/직렬화/블루프린트와 연동할 수 있다. std::vector는 등록이 안됨
InputAction은 행동자체를 정의, IA_Jump, IA_Move, IA_Attacke등
Input Mapping Context는 어떤 키/패드를 어떤 IA에 연결할지 정의
실행중인 언리얼이 클래스/변수/함수의 정보와 설정을 알 수 있게 만드는 시스템
흐름
.generated.h, .gen.cpp 같은 자동 생성 코드를 만든다 -> GENERATED_BODY()는 이 자동생성 코드와 우리가 작성한 클래스와 연결되는 자리다.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은 저장할 데이터를 담아 디스크의 저장 슬롯에 쓰고, 나중에 다시 읽기 위한 데이터 객체. 게임을 껐다 켜도 저장파일은 남음
PrimaryAssetId로 식별되는지 안되는지 차이, 특히 AssetManager가 관리/로드할 수 있는 데이터에셋이 PrimaryDataAsset이고, UDataAsset은 일반적인 데이터에셋
AnimNotify는 애니메이션의 한 시점에 한 번 실행되는 알림
AnimNotifyState는 애니메이션의 일정 구간동안 유지되는 알림
RootMotion은 애니메이션 안의 Root Bone 이동량을 읽어서, 캐릭터의 실제 위치와 회전도 같이 이동시킴
In-place는 Root Bone은 제자리에 있고, 걷는 모션만 재생, 실제 캐릭터 이동은 코드가 처리