*이 글은 유니티 6 정식 릴리즈 이후에 작성된 글로써, 현 시점 최신 버전인 Entities 1.3.5 를 쓰고 있다.
첫 글에서 이제 시작이라는 느낌으로 끝을 맺었지만
이론 부분은 끝나지 않았다.
기본적인 컨셉을 유니티에서는 어떻게 따라야 하는지 알기 떄문이다.
ECS는 쉽게
(1) Entity 라는 껍데기, 정체성, Identifier, 특정 지을 수 있는 무언가.
(2) Component 라는 꼬리표, 태그, 정보
(3) System 이라는 로직, 실행부로 구분 할 수 있다.
(1) Entity 만들기.
우선, 헬로 큐브 프로젝트의 _Common 폴더의 ExecuteAuthoring을 보자.
ECS에서는 일종의 명명 규칙처럼,
엔티티로 만들기 위한 코드 명 뒤에 Authoring 이라고 붙인다.
Entity의 사전 정의를 고려 해보면, 참으로 적절한 네이밍 같기도 하다.
public class ExecuteAuthoring : MonoBehaviour
{
public bool MainThread;
public bool IJobEntity;
public bool Aspects;
public bool Prefabs;
public bool IJobChunk;
public bool Reparenting;
public bool EnableableComponents;
public bool GameObjectSync;
public bool CrossQuery;
public bool RandomSpawn;
public bool FirstPersonController;
public bool FixedTimestep;
public bool StateChange;
public bool ClosestTarget;
class Baker : Baker<ExecuteAuthoring>
{
public override void Bake(ExecuteAuthoring authoring)
{
var entity = GetEntity(TransformUsageFlags.None);
if (authoring.MainThread) AddComponent<ExecuteMainThread>(entity);
if (authoring.IJobEntity) AddComponent<ExecuteIJobEntity>(entity);
if (authoring.Aspects) AddComponent<ExecuteAspects>(entity);
if (authoring.Prefabs) AddComponent<ExecutePrefabs>(entity);
if (authoring.IJobChunk) AddComponent<ExecuteIJobChunk>(entity);
if (authoring.GameObjectSync) AddComponent<ExecuteGameObjectSync>(entity);
if (authoring.Reparenting) AddComponent<ExecuteReparenting>(entity);
if (authoring.EnableableComponents) AddComponent<ExecuteEnableableComponents>(entity);
if (authoring.CrossQuery) AddComponent<ExecuteCrossQuery>(entity);
if (authoring.RandomSpawn) AddComponent<ExecuteRandomSpawn>(entity);
if (authoring.FirstPersonController) AddComponent<ExecuteFirstPersonController>(entity);
if (authoring.FixedTimestep) AddComponent<ExecuteFixedTimestep>(entity);
if (authoring.StateChange) AddComponent<ExecuteStateChange>(entity);
if (authoring.ClosestTarget) AddComponent<ExecuteClosestTarget>(entity);
}
}
}
public struct ExecuteMainThread : IComponentData
{
}
초보자를 위한 코드가 참 성의없다고 느껴진다.
boolean으로 잔뜩 정의되어 있는 변수들은,
Hello Cube의 예제가 14개이기 때문에,
예제의 각 Scene에서 똑같은 Authoring 코드를 재활용하기 위한 목적이다.
각 Scene에 들어있는 SubScene을 열어보면, 엔티티화 시킬 게임 오브젝트에 Authroing 컴포넌트가 붙여져 있고, 예제에 맞는 bool 표시가 체크되어 있다.
첫번째 예제, MainThread 를 보면,
MainThread 가 True 일 경우, AddComponent<ExecuteMainThread>(entity) 를 호출하도록 되어있다.
GetEntity() 함수는 Authoring할 GameObject 를 엔티티화 시켜서 등록하는 역할이다.
ExecuteMainThread로 명시되어있는 컴포넌트는 흔히 유니티에 쓰이는 컴포넌트들이 아니라,
ECS의 Component다.
코드 예제 아래를 보면 IComponentData 라는 인터페이스로 구현 된 "구조체" ExecuteMainThread 를 컴포넌트로 쓰겠다는 의미이다.
그리고, Baker 라는 특이한 클래스를 상속 받고 있는데
그래픽 렌더링에서 생각하는 그 Bake가 맞다.
ECS에서는 GameObject 를 SubScene를 로드하면서, Entity로 Bake (굽는) 하는 방식이다.
Baker 클래스는 외부에도 선언해도 되지만.. 그럴 일이 있을까?
원래 이전 ECS 버전에서는 SubScene이란 개념도 없고, 미리 Baking 하는 과정도 없었다.
실시간으로 GameObject to Entity 로 컨버터하는 개념이였는데
유니티에서는 편의성과 유연성 대신에 극한의 성능을 뽑고자 했다고 설명하고 있다.
유니티 Discussion을 보면, 납득하지 못하는 사람도 있지만
대체적으로 현명한 선택이라는 평가가 많다.
그러면, 요약하겠다.
(1) Entity 화를 시키려면,
기존 GameObject에 Baker Class를 구현해놓으면
Entity 처리를 하는 SubScene에서 자동으로 Baking 작업을 진행한다.
(2) Baker 클래스 내에서는
Entity 화 시킬 GameObject나 컴포넌트를 Entity의 구조체로써 등록하도록 구성하여
엔티티를 생성한다.
(3) Component는 여러개 동시에 Entity의 태그에 해당되는 컴포넌트로써 나중에 System을 통해
우리가 Bake한 GameObject의 Entity를 찾는데 도움을 준다.
여기까지만 이해하면 딱 Entity를 만드는 과정으로 생각하면 된다.
이해를 돕기 위해 추천하는 문서들은 다음과 같다.
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/conversion-subscenes.html
Subscenes overview | Entities | 1.3.5
Subscenes overview The entity component system (ECS) uses subscenes instead of scenes to manage the content of your application. This is because Unity's core scene system is incompatible with ECS. You can add GameObjects and MonoBehaviour components to a s
docs.unity3d.com
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/baking-overview.html
Baking overview | Entities | 1.3.5
Baking overview Baking is a process that converts GameObject data in the Unity Editor (authoring data) into entities written to Entity Scenes (runtime data). Baking is a non-reversible process that turns a performance-intensive but flexible set of GameObje
docs.unity3d.com
이 단번에 이해하기 힘든 Baking / SubScene 은
예제부터 보지 말고, Docs 부터 차근차근 읽어야 한다는걸 깨닫게 하였다.
(2) Component 뿌시기
(3) Component는 여러개 동시에 Entity의 태그에 해당되는 컴포넌트로써 나중에 System을 통해우리가 Bake한 GameObject의 Entity를 찾는데 도움을 준다.
ECS & DOTS를 처음 접하는 사람들은
Archtype에 대해 알게되는데.
어떤 엔티티 그룹들을 특정 할 수 있는 방법은
컴포넌트라는 꼬리표의 조합을 가진 엔티티들을 찾는 것이라고 배웠을 것이다.
일반적으로, 우리가 플레이어의 GameObject를 만들었다면,
어떤 컴포넌트가 있을까?
플레이어의 Trnasform, PlayerTag, Move, Jump, Attack 등
많은 기능들을 바로바로 생각할 것이다.
그러면 수많은 컴포넌트들이 있을 때,
플레이어를 특정하려면?
반대로 플레이어가 가진 컴포넌트들을 검색해서 (Query) 플레이어를 특정할 수 있다.
자! 엔티티 여러분들!! (Query) 여러분 중에 PlayerTag / Move / Jump / Attack / Transform 을 모두 가지고 있는 분 손드세요!! Player GameObject 였던 Player Entity가 있군요!
우리가 어떤 사물을 생각 할 때,
사물의 특징들을 여럿 나열 할 것이다.
이런 특징들을 컴포넌트라고 생각하면 된다.
컴포넌트는 망할 Hello Cube 예제마냥, 텅빈 구조체냐?
당연히 아니다.
Component에는 여러 자료형들을 집어넣어서,
어떤 데이터를 쓸 것인지 저장 할 수 있도록 한다.
Transform 같은 경우, 위치값은 엔티티마다 다를 것이다.
Query를 통해, Transform 을 가진 엔티티들을 System 구현 부에서 가져온다.
(Transform 이면 사실상 모든 엔티티겠지만..)
Trnasform에는 Position / Rotation / Scale에 대한 값들이 기록되어있다는 의미이다.
System 부분들은 여러 종류가 있고,
혼란스러운 부분이 많아 다음 강의 자료로 뵙겠다.
하지만, Hello Cube로 고통 받았을 분들을 위해 알려드리고 싶은게 있다.
거의 모든 DOTS 설명 자료중에는
개념이나 컨셉 이후에
ECS
C# Job System
Burst Compiler
Mathematics
Collections
를 항상 묶어서 패키지로 소개하는데.
이 부분 그냥 지나치면 .System 구현부에서 고통 받는다.
ECS 아래 4개 모두 사실 상, System 단에서 사용되기 때문에
Hello Cube는 Entities 샘플인데도 불구하고
잔인하게 아래 3개 패키지가 혼용되어 사용된다. 어떠한 설명도 없이..
꼭 숙지하고, 이 부분에서는 왜 이걸 썼는가에 대해 코드를 보며 이해할 수 있다.
-- Mathematics
혹시 딥러닝에 사용되는 Tensor 타입 형에 대해 아는가?
Tensor는 Vector / Array 연산을 위한 다차원 자료형이다.
Mathematics 패키지도 비슷하다.
유니티가 아닌 외부 C# 에서는 Vector3가 아니라 int의 배열로 표현 될 것이다.
Mathematics 은 배열이 아니라 IntMatrix FloatMatrix 같은 새로운 자료형들을 제공한다.
Vector3 는 관리 (Managed System) 가 필요하기 때문에 컴포넌트에서 그대로 사용 할 수가 없고,
Burst Compiler도 동작하지 못하게 한다.
이를 간편하면서도 동일한 효과를 내주도록 자료형과 오퍼레이터를 제공하는게 Mathematics 이다.
그냥 사칙연산이겠구나~ 하고 넘어가지 말라는 이야기다.
-- Collections
Collections 안에는 Native 라는 이름이 붙여진 자료형들이 많다.
유니티의 GameObject들은 메인 스레드가 아니면 불안정하다고 한다.
하지만 ECS나 멀티 스레드에서 유니티 오브젝트를 사용 할 수 있게, 제약을 걸고 있는데
그게 바로 Collections다.
-- Burst Compiler
이 부분에 대해서는 컴파일러에 대해 전문가가 아닌 나는 제대로 설명할 수는 없지만
나름대로 리서치 한 걸 설명한다면
유니티는 Burst를 포함하여 3개의 컴파일러가 존재한다.
일반적으로 쓰이는 IL2CPP(쉽게 말해, C++언어로 변환 후, 컴파일링), JIT (필요할 때, 컴파일링)
그리고 Burst Compiler가 있는데
아주 러프하게 플랫폼에 맞게 네이티브 변환한다고 이해하면 된다.
ECS나 Job System은 따로 설명하진 않겠다.
'Game Dev > Unity ECS & DOTS' 카테고리의 다른 글
[ECS&DOTS] NSprite 머리 쪼개기 (2) 우선, 샘플 프로젝트부터 공략하자. (2) (8) | 2024.11.11 |
---|---|
[ECS&DOTS] NSprite 머리 쪼개기 (1) 우선, 샘플 프로젝트부터 공략하자. (1) | 2024.11.08 |
4. ECS 워크플로 이해하기- ECS & DOTS 완전 정복하기. Feat. 안 반가운 큐브 프로젝트 (4) | 2024.11.06 |
3. IJobEntity 예제, 관련 Docs 파헤치기 - ECS & DOTS 완전 정복하기. Feat. 안 반가운 큐브 프로젝트 (2) | 2024.11.05 |
1. ECS, DOTS란 무엇이냐? - ECS & DOTS 완전 정복하기. Feat. 안 반가운 큐브 프로젝트 (3) | 2024.10.31 |