[DOTS] Entities and Components

황교선·2023년 8월 9일
0

DOTS

목록 보기
3/5

Entities and Components 유튜브 링크

기존 개념

UnityEngine.GameObject

  • C# class
  • UnityEngine.Component 인스턴스들의 컨테이너
  • Transform 컴포넌트를 항상 소유함
  • 다른 GameObject의 자식이 될 수 있음

UnityEngine.Component

  • C# class
  • 게임 루프 중에 Update 메소드와 같은 특수 메소드들이 특정한 시점에 호출이됨
  • 다른 managed object들을 레퍼런스하고 있을 수 있음

Managed objects의 제한점

Entities and Components

Entity

  • 정수 id
  • 각 컴포넌트가 중복되지 않고 하나씩만 결합되어 있음
    • foo 컴포넌트 라는 것이 있을 때, 각 엔티티는 하나의 foo 컴포넌트만 소유할 수 있음
  • GameObject의 Components와는 달리 Entity의 Components는 Unmanaged Object

Unity.Entities.IComponentData

  • C# struct
    • class일 수도 있음
  • id를 통해 entities들을 레퍼런스하고 있을 수 있지만, 일반적으로 managed objects들이 아님
  • 컴포넌트는 일반적으로 데이터로만 이루어져 있고 메소드가 없음
  • 빽빽하게 차있는 배열을 퀴리를 통해 효율적으로 접근할 수 있음
public struct Movement : IComponentData
{
  public float3 Direction; // could be found in mathmatics package
  public float Speed;
}

World

  • Entity를 위한 컨테이너
  • 월드 안에 있는 Entity는 각각의 고유한 id를 갖고 있음
    • 다른 월드에 있는 다른 Entity와 id가 겹칠 수 있음
  • 보통은 하나의 World만 있으면 되지만 논리적 분류가 필요할 때 추가적인 World를 생성하면 편리함
    • ex) DOTS netcode packed
      • World for server
      • World for each client

EntityManager

  • 월드 안에 있는 Entities들을 관리함
  • 메소드
    • CreateEntity()
    • DestoryEntity()
    • AddComponent()
    • RemoveComponent()
    • GetComponent()
    • SetComponent()

Archetype

  • 동일한 컴포넌트 조합으로 이루어진 Entities들의 원형
  • Each unique combination of components

Chunk

  • 일정한 크기로 이루어진 Entities와 component를 담고 있는 Archetype의 블럭

위의 그림을 보며 각 개념에 대해 이해를 해보겠습니다.

만약 Compoennt A, B로 이루어진 Entity에 Component C가 추가된다면, 그 Entity의 Component는 A, B, C가 되므로 첫 번 째 아키타입의 청크로 이동해야합니다. 이렇게 이동하는 과정을 포함하여 엔티티 생성, 파괴, 컴포넌트 추가 그리고 컴포넌트 삭제 등을 EntityManager가 처리하기 때문에 우리가 직접할 필요는 없습니다. 위에서 언급된 생성과 파괴, 그리고 컴포넌트 추가 및 삭제 연산은 구조적 변화 연산(structural change operation)이라고 불리고 단순히 컴포넌트의 데이터의 값을 읽거나 수정하는 것은 구조적 변화 연산이 아닙니다.

Chunk는 항상 최대 128개의 엔티티의 수용량을 갖습니다. 현재 예제에서는 이 Chunk가 수용량이 128이지만, 세 개의 엔티티만을 저장하고 있다고 가정합니다. Chunk의 Archetype은 세 개의 컴포넌트를 갖고 있으므로 Chunk의 구성으로는 Entity ID 배열과 각 컴포넌트의 배열이므로 총 4개의 배열을 갖습니다.

첫 번 째 엔티티는 인덱스 0인 위치에, 두 번 째 엔티티는 인덱스 1인 위치에, 세 번 째 엔티티는 인덱스 2인 위치에 놓입니다. Chunk는 빽빽하게 관리됩니다. 예를들어 엔티티가 추가될 때는 빈공간 중 가장 첫 번째 위치에 추가되며, 엔티티가 제거될 때는, 가장 마지막의 엔티티가 빈 자리를 메꾸기 위해 이동합니다.

각 컴포넌트의 크기는 동일한 갯수를 갖고 있지만, 크기가 항상 동일하지는 않습니다.

EntityManager는 Entity metadata 배열을 관리하고 있기 때문에 우리는 엔티티 ID로 찾아볼 수 있습니다. 각 엔티티는 metadata array 슬롯 인덱스를 갖고 있고 이 슬롯 인덱스를 통해 슬롯에 접근합니다. 슬롯은 Chunk의 포인터를 갖고 있고, 만약 어떤 인덱스에는 아무런 엔티티를 관리하지 않을 때 Chunk 포인터는 null입니다. 위의 그림으로는 인덱스 1, 2, 5가 null이게 됩니다.

엔티티가 삭제되고 난 후 인덱스를 재사용하기 위해서 버전 넘버를 사용합니다. 인덱스가 삭제될 때마다 버전 넘버를 증가시키기 때문에 현재 저장된 것과 버전 넘버가 일치하지 않는다면 이미 삭제됐거나 아예 생성되지 않았음을 의미합니다.

Query

  • 특정한 컴포넌트 셋을 갖고 있는 엔티티를 효율적으로 찾음

A와 C를 갖고 있는 컴포넌트를 찾는 쿼리를 실행하면 다음과 같습니다.

결과 중에 제외하고 싶은 컴포넌트가 있다면 제외 할 수 있습니다. A와 C를 포함하지만 B를 제외한 결과는 세 번째만이므로 위 그림의 파란색 블럭이 됩니다.

Job에서 Entities와 Components에 접근하기 위해서는 다음 두 가지 Job 타입을 이용할 수 있습니다.

  1. IJobChunk
    • Query에 맞는 모든 Chunk를 iterate함
      • 각각의 Chunk에서 각 Entity와 각 Components에 접근이 가능
    • 편하지는 않지만, low-level control이 가능함
  2. IJobEntity
    • 직접적으로 Entities를 iterates함
    • 몇 가지 경우에서는 작동하지 않기 때문에 IJobChunk를 이용해야함

그 외 개념

  • Baking
    • Entity는 직접적으로 유니티 씬에 포함될 수 없기 때문에 Baking이라는 build time process를 거쳐야는데 이를 통해 GameObject가 Entity로 변환되어 Subscene에 들어감
  • Entity Subscene
    • Baking을 통해 각 하나씩의 Entity를 만들어 Subscene에 들어가게 됨
  • Baker
    • 각 GameObject의 각 Component는 Baker class를 통해 Entity의 컴포넌트 값을 추가하고 설정함
  • Baking System
    • (옵션)
profile
성장과 성공, 그 사이 어딘가

0개의 댓글