엑터와 컴포넌트
언리얼 엔진은 월드안에 엑터들이 존재하며 엑터들은 컴포넌트들을 가지고 있다. 여기서 엑터는 오로지 월드위에만 존재 할 수 있으며 다른 엑터에 속할 수 없다.(월드 상의 트랜스폼 배치를 이야기하는 것 이다. 클래스에서 다른 엑터의 참조를 가지는 등은 당연히 가능) 대신 엑터가 가지는 컴포넌트들이 엑터 아래에서 계층적으로 존재한다. 엑터 바로 아래에 루트 컴포넌트가 존재하며 그 아래 계층적으로 존재한다.
엑터
ㄴ 루트 컴포넌트
ㄴ컴포넌트
ㄴ컴포넌트
ㄴ컴포넌트
ㄴ컴포넌트
그럼 계층적인 트랜스폼은 어떻게 표현할까? 컴포넌트 중 씬 컴포넌트는 트랜스폼을 가지는 컴포넌트이다. 이러한 컴포넌트들의 계층으로 계층적인 트랜스 폼을 표현 가능하다. 여기서 루트 컴포넌트는 반드시 씬 컴포넌트나 그의 자손(C++ 상속)이어야하며 루트 컴포넌트의 트랜스폼이 곧 엑터의 트랜스폼이 되는 셈이다.
엑터
엑터는 월드에 배치되는 오브젝트같은 존재이다. 엑터를 표현하는 클래스는 다음과 같은 구조를 가진다. (sudo 코드)
엑터
{
uproperty들 : 컴포넌트 포인터, 다른 변수등
생성자
begin함수
tick함수(deltatime)
그외 여러 이벤트나 커스텀 함수
}
uproperty
여기서 uproperty는 UPROPETY()매크로 함수 바로 아래에 선언된 멤버 변수들을 의미한다. 이러한 변수들은 에디터 인스펙터에서도 뜨며 여러 언리얼 기능과 호환이되는 엑터의 프로퍼티가 되게 된다. 특히 컴포넌트 포인터는 컴포넌트 생성함수를 통해 자신이 생성한 컴포넌트를 넣을 시 자신이 소유한 컴포넌트를 나타내게 되며 인스펙터에 컴포넌트가 나타나게 된다. 원한다면 uproperty가 아닌 일반 멤버 변수도 당연히 만들어 사용할 수 있다.
생성자
엑터 클래스의 c++ 생성자이다. 이는 사용자 관점에서 에디터에서 월드에 배치할 때 호출된다고 볼 수 있다. 아니면 여기서 설정되는 프로퍼티값들이 기본값처럼 사용된다고 봐도 무방하다. 만약 여기서 값을 설정하고 해당 클래스를 에디터 맵에 배치하면 해당 프로퍼티 값들은 생성자에서 초기화 해준 값들을 가진체 배치된다. 하지만 직접 에디터에서 다른 값으로 수정하고 게임을 실행하면 에디터에서 설정한 값을 가진다. 게임 실행 시 호출되는 개념이 아니기 때문이다. 물론 인게임에서 엑터가 생성되면 생성자는 호출될 것 이다.
BeginPlay
게임 실행시 호출되는 함수이다. 또는 인게임에서 생성시 생성자 이후 호출되는 함수이다.
Tick
업데이트 함수이다. 매 프레임 호출되며 deltatime을 받는다.
그외
충돌 이벤트 오버라이드용 함수나 우리가 만든 함수들이 존재할 수 있다.
프리팹
이렇게 생성한 엑터 클래스는 그 자체로 하나의 프리팹처럼 쓸 수 있다. 엑터 클래스는 자신의 로직과 동시에 소유한 컴포넌트와 기본값들을 가질 수 있기에 프리팹 그 자체로 볼 수 있는 것이다.
여기서 프리팹의 특성을 하나 볼 수 있는데 생성자에서 설정해준 기본값은 다음과 같이 동작한다.
1. 엑터 배치시 기본값으로 초기화
2. 생성자에서 기본값 수정 시 이미 배치된 엑터중 해당 프로퍼티의 값이 기존 기본값이 었던 프로퍼티들은 다 따라 바뀜
정석적인 프리팹의 갱신 형태이다.
기본 엑터들
언리얼에서는 기본적으로 제공해주는 엑터들이 존재한다. 베이스 엑터의 자손들이며 굉장히 강력한 기능들을 제공해주고 대부분의 언리얼 기능들이 이 엑터들과 연관지어 제공되기에 사실상 필수적으로 사용해야하는 엑터들이다.
Actor
최상위 엑터 베이스 클래스이다. 모든 엑터는 이를 상속받으며 우리가 엑터를 만들고자 한다면 이 클래스 또는 이 클래스의 자손을 상속받으면 된다.
Pawn
제어 가능한 엑터를 나타난다. 플레이어, npc등을 나타낸다.
Charactor
폰의 자손으로 이족 보행형 아바타 Pawn이다.
Controller
폰에 빙의하여 제어 가능한 엑터로 pawn의 움직임로직을 contoroller를 통하게 구현하면 같은 로직으로 플레이어와 npc를 동시에 구현가능하다.
platerContoroller
컨트롤러의 자손응로 사용자의 키보드 입력등을 받는데 최적화된 컨트롤러이다.
컴포넌트
컴포넌트는 엑터에 붙어 작동하는 컴포넌트이다. 엑터처럼 생성자, begin, tick을 가진다. 우리가 직접 만들 수도 있지만 강력한 기능을 제공해주는 기본 컴포넌트들이 많이 존재한다. 다음과 같은 것들이 있다.
ActorComponent
최상위 컴포넌트이다. 모든 컴포넌트는 이를 상속받으며 우리가 컴포넌트를 만들고자 한다면 이 클래스 또는 이 클래스의 자손을 상속받으면 된다.
SceneComponent
트랜스폼 기능이 있는 컴포넌트이다. 트랜스폼이 있는 컴포넌트를 만들고 싶다면 이를 상속받으면 된다.
PrimitiveComponent
씬 컴포넌트의 자손으로 거기에 기하구조까지 추가된 컴포넌트이다. 콜리전이나 렌더링 관련 기능들이 있다. 마찬가지로 관련 컴포넌트를 만들고 싶다면 이를 상속받아 만들자.
컴포넌트와 컴포넌트 포인터 프로퍼티
컴포넌트는 엑터에서 createdefaultsubobject함수를 통해 생성할 수 있다. 그리고 컴포넌트의 setupattachment함수를 통해 다른 컴포넌트의 자식으로 들어갈 수 있다. 사실 액터에서 위 함수로 컴포넌트를 생성만해도 실제 액터 아래에 컴포넌트가 생성되며 tick같은 기능도 실제로 작동한다. 그리고 setupattachment함수를 통해 특정 위치에 들어갈 수도 있다. 하지만 보통 액터에서 컴포넌트를 생성할때는 액터의 컴포넌트 포인터 프로퍼티를 하나 만들고 컴포넌트를 생성하여 얻은 포인터를 거기에 넣은 뒤 자신의 특정 컴포넌트 아래에 넣어 관리한다. 이때 컴포넌트 포인터 프로퍼티를 사용하는 이유는 다음과 같다.
1. 자신이 가진 컴포넌트를 인스펙터나 계층구조 창에서 gui로 보고 관리하려면 시각화 설정이 된 컴포넌트 포인터 프로퍼티에 해당 컴포넌트의 포인터가 들어가야한다. 실제로 컴포넌트가 생성되어 작동한다고 해도 해당 프로퍼티에 들어가있지 않다면 gui에 표시되지않는다.
2. gui에 시각화할 생각이 없더라도 당연히 액터에서 자신의 컴포넌트에 대한 참조를 가지고 있어야 그에 대한 사용 및 관리가 가능할 것이다. 이때 언리얼의 다른 기능들과의 추가적인 호환성을 고려하여 컴포넌트 포인터 프로퍼티로 해당 컴포넌트의 참조를 관리하는 것이다.
그래서 결론은 액터의 컴포넌트를 생성할 것이라면 왠만해선 컴포넌트 포인터 프로퍼티로 해당 컴포넌트를 관리하게 될 것이다.추가로 컴포넌트 포인터 프로퍼티는 자신의 컴포넌트를 담는 용도로만 사용되는 것이 아니다. 컴포넌트 포인터 프로퍼티를 인스펙터에서 보이도록 설정하여 만들고 초기화하지 않으면 인스펙터에 빈칸에 해당하는 컴포넌트 포인터 프로퍼티가 나타날 것이다. 이때 다른 액터의 컴포넌트를 가져와 채운 뒤 해당 참조를 사용하여 다른 컴포넌트에 접근하는 식으로 사용할 수 있다. 아니면 꼭 인스펙터를 통한 것이 아닌 그냥 로직상에서 다른 컴포넌트의 참조를 저장하는 용도로도 당연히 사용한다.
블루 프린터
언리얼 엔진에는 각종 클래스들을 코딩대신 블루 프린터라는 GUI 그래프로 표현할 수 있다. 이벤트에서 호출하는 함수 블록들을 연결하는등으로 구현한다. 엑터, 컴포넌트 클래스, anim instance(유니티의 animator + 스스로 상태 업데이트 까지하는 애니메이션 기능)등을 블루 프린터로 구현할 수 있다.
이러한 블루프린터들은 처음부터 블루프린터로 만들 수도 있지만 c++클래스로 해당 요소를 만들고 이를 상속받은 블루프린터를 만드는 것도 가능하다. 그러면 그 기능들은 그대로 받으며 추가적인 수정이 가능해진다. 언리얼 엔진에서 많이 사용되는 개발 패턴이 기본적이고 코딩하기 좋은 기능들을 c++ 클래스로 만들고 이를 상속받은 블루 프린터로 마무리하여 엑터, 컴포넌트, anim instance등을 만들어 사용하는 것이다. 어느정도 수준의 기능들은 코딩으로 만들기 편하지만 단순히 계층구조 추가나 값 설정들은 블루프린터가 편하기에 좋은 패턴이다.
UObject
언리얼 엔진 에디터에서 작동되는 대부분의 클래스들의 최상위 클래스는 UObject이다. 엑터 ,컴포넌트 등이 다 UObject의 자손이다. 엑터는 특별히 클래스 이름앞에 A를 붙이지만 그 외의 UObject 자손들은 클래스 이름 앞에 U를 붙인다. USceneComponent등이다.
UObject는 가비지 컬렉터, 자동 에디터 통합, 시리얼라이제이션등의 일반적인 기능을 제공하기에 대부분의 클래스가 상속받는다. 가끔 이러한 UObject의 자손이 아닌 클래스가 있는데 이들은 이름앞에 F를 붙인다. FVector등이 예시이다.
'게임엔진 > 언리얼 엔진 5' 카테고리의 다른 글
[언리얼 엔진5][기초 3장]렌더링 리소스 기초 (0) | 2023.04.23 |
---|---|
[언리얼 엔진5][기초 2장] 충돌 감지 (0) | 2023.04.23 |