[언리얼 엔진] 오브젝트 처리
- ⭐ Game Programming/Unreal Document
- 2021. 12. 2.
언리얼 오브젝트 처리
자동 프로퍼티 초기화
UObject는 생성자 호출 전 초기화시 자동으로 0으로 채워진다. 클래스, UProperty, 네이티브 멤버 모두에게 적용된다. 이후 멤버는 클래스 생성자의 커스텀 값으로 초기화 가능하다.
레퍼런스 자동 업데이트
AActor 또는 UActorComponent가 소멸되거나 플레이에서 제거되면, 리플렉션 시스템에 보여지고 있던 모든 레퍼런스는 자동으로 null이 된다. 허상 참조를 예방하여 문제의 소지를 줄인다는 장점이 있지만, 다른 코드부분에서 AActor와 UActorComponent 포인터를 소멸시키는 경우 null 이 된다는 것을 뜻한다. null 검사 안정성이 높다.
자동 업데이트 기능은 UPROPERTY로 마킹되어 있거나 언리얼 엔진 컨테이너 클래스에 저장된 UActorComponent 또는 AActor 레퍼런스에만 적용된다. raw 포인터에 저장된 오브젝트 레퍼런스는 언리얼 엔진이 알수 없어 자동으로 null 되거나, 가비지 컬렉션을 방지되지 않는다. UProperty가 아닌 오브젝트 포인터가 필요한 경우, TWeakObjectPtr을 고려해 볼수 있다. 가비지 컬렉션을 바지하지는 않지만 접근전 유효성 검사를 할수 있고, 가리키는 오브젝트가 소멸된 경우 null 설정도 가능하다.
에디터에서 애셋을 'Force Delete'(강제 삭제)한 경우에는 참조된 UObject UProperty가 자동으로 null이 된다.
Serialization
UObject가 Serialize 될 때, 모든 UProperty 값은 명시적으로 "transient" 마킹 또는 생성자 이후 기본값에서 미변경 상태가 아닌 이상 자동으로 읽고 쓰기 가능하다. UProperty가 추가, 제거 될 때, 기존 콘텐츠 로드에는 영향이 없다. 새 프로퍼티는 새 CDO에서 기본값을 복사해 온다. 제거된 프로퍼티는 무시된다. 커스텀 작동 방식이 필요한 경우, UObject::Serialize 함수를 덮어쓰면 된다.
프로퍼티 값 업데이트하기
UClass의 클래스 디폴트 오브젝트(CDO)가 변경되면, 엔진은 그 클래스의 모든 인스턴스 로드시 알아서 변경사항을 적용한다. 주어진 오브젝트 인스턴스에 대해 업데이트된 변수 값이 이전 CDO 값과 일치한다면, 새로운 CDO에 저장된 값으로 업데이트 된다. 변수 값이 다른 경우, 그 변수가 의도적으로 설정되었다 가정하여 변경사항을 보존한다.
에디터 통합
UObject와 UProperty는 에디터에 인식되며, 에디터는 별도의 코드를 작성할 필요 없이 이 값을 자동으로 노출시킬 수 있다. 선택적으로 블루프린트 비주얼 스크립팅 시스템으로 통합(integration)이 가능하다. 변수와 함수의 노출 및 접근 여부를 제어할 수 있는 옵션이 많이 있다.
런타임 유형 정보 및 형변환
UObject는 언리얼 엔진 리프렉션 시스템의 일부로, 항상 자신이 무슨 UClass 인지 알고 있어 형변환을 실시간으로 할 수 있다. 네이티브 코드에서, 모든 UObject클래스에는 부모 클래스로 설정된 커스텀 Super typedef가 잇어 덮어쓰기 행위에 대한 제어가 쉽게 가능하다.
class AEnemy : public ACharacter
{
virtual void Speak()
{
Say("Time to fight!");
}
};
class AMegaBoss : public AEnemy
{
virtual void Speak()
{
Say("Powering up! ");
Super::Speak();
}
};
MegaBoss는 Powering Up! Time to fight! 라 말하게 된다.
템플릿 Cast 함수를 사용해서 베이스 클래스에서의 오브젝트를 좀더 파생된 클래스로 안전하게 형변환 하거나 IsA를 사용해서 오브젝트가 특정 클래스의 것인지 질의 할 수 있다.
class ALegendaryWeapon : public AWeapon
{
void SlayMegaBoss()
{
TArray<AEnemy> EnemyList = GetEnemyListFromSomewhere();
// The legendary weapon is only effective against the MegaBoss
for (AEnemy Enemy : EnemyList)
{
AMegaBoss* MegaBoss = Cast<AMegaBoss>(Enemy);
if (MegaBoss)
{
Incinerate(MegaBoss);
}
}
}
};
가비지 컬렉션
언리얼에서는 더이상 참조되지 않거나 명시적으로 소멸 예약시킨 UOBject를 주기적으로 정리하는 가비지 컬렉션 스키마를 사용한다. 엔진에서는 레퍼런스 그래프를 만들어 어느 오브젝트가 아직 사용중이고 어느 것이 고아가 되었는지 판단한다. 이 그래프 루트에는 "루트 세트"라 지정된 오브젝트 세트가 잇다. 어떤 오브젝트라도 루트 세트에 추가할 수 있다. 가비지 컬렉션이 발생하면 엔진은 루트 세트부터 시작하여 알려진 UObject 레퍼런스 트리를 검색하여 참조된 오브젝트 전부를 추적할 수 잇다. 참조되지 않은 오브젝트, 트리 검색에서 찾지 못한 것들을 더이상 필요치 않은 오브젝트라 가정하고 제거한다.
전형적으로 살려두고자 하는 오브젝트는 UPROPERTY 레퍼런스를 유지하거나 그에 대한 포인터를 TArray 또는 다른 언리얼 엔진 컨테이너 클래스에 저장해야한다. 액터와 그 컴포넌트는 예외인데, 액터는 보통 자신이 속한 레벨처럼 루트 세트로 다시 링크되는 오브젝트에, 그리고 액터의 컴포넌트는 액터 자체에 레퍼런싱 되기 때문이다. 액터는 자신의 Destroy 함수를 호출하여 명시적으로 소멸 마킹할 수 있는데, 이는 진행중인 게임에서 액터를 제거하기 위한 표준적인 방식이다. 컴포넌트는 DestroyComponent 함수로 명시적으로 소멸시킬 수 있으나, 보통은 소유 액터가 게임에서 제거될 때 소멸된다.
고아가 된 오브젝트 식별을 위한 도달 가능성 분석 멀티스레드 처리, 컨테이너에서 액터를 최대한 빠르게 제거할 수 있도록 최적화된 언해시 코드등이 있다. 가비지 컬렉션 방법 및 시점을 보다 정교하게 제어할수 있는 기능도 프로젝트 세팅의 엔진 - 가비지 컬렉션에서 제공된다.
네트워크 리플리케이션
UObject 시스템에는 네트워크 통신과 멀티 게임을 하기위한 함수 세트가 포함되어있다 관련 문서 참조