본문 바로가기
개발/Unity

[Unity][DOTS] ECS & C# Job System, 샘플 프로젝트 따라잡기 #2

by 가리봉맨 2019. 3. 29.
반응형

샘플 프로젝트는 https://github.com/Unity-Technologies/EntityComponentSystemSamples 에서 받아볼 수 있다.

샘플 프로젝트의 예제는 총 일곱 개다. HelloECS 폴더에 여섯 개, Advanecd 폴더 아래 한 개가 들어있다. HelloECS 여섯 개 예제 중 첫 번째 예제인 HelloCube_01_ForEach 씬(scene)를 파헤쳐 보겠다.

Project 뷰를 보면 아래 그림과 같이 HelloCube_01_ForEach 폴더 안에 씬, README 문서, 세 개의 C# 스크립트가 들어있다. 

README 파일의 내용만으로 이 예제의 전체 구조와 동작을 파악할 수 있다. ECS의 각 요소인 Entity, Component, System은 번역하지 않고 영어 단어 그대로 쓰겠다. 이 예제는 한 쌍의 큐브가 회전하는 간단한 ECS 시스템을 보여준다. ECS는 데이터(data)와 로직(functionality)을 분리해서 처리하는데, 데이터는 Component에 저장하고 로직은 System으로 구현한다.

ComponentSystem을 상속받아 작성한 RotationSpeedSystem은 Entities.ForEach 구문으로 각 Entity를 반복(iterate) 처리한다. 이 예제에는 Entity가 딱 한 개지만, 더 많은 Entity를 씬에 추가하면 RotationSpeedSystem이 씬에 존재하는 모든 Entity의 데이터를 갱신한다. 

public class RotationSpeedSystem : ComponentSystem
{
  protected override void OnUpdate()
  {
    Entities.ForEach((ref RotationSpeed rotationSpeed, ref Rotation rotation) =>
    {
      var deltaTime = Time.deltaTime;
      rotation.Value = math.mul(math.normalize(rotation.Value),
                                quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
    });
  }
}

단, 해당 Entity는 RotationSpeed Component를 갖고 있어야 한다.

[Serializable]
public struct RotationSpeed : IComponentData
{
	public float RadiansPerSecond;
}

참고로 ComponentSystem은 Entities.ForEach를 메인 쓰레드에서 실행한다. 멀티 코어를 사용하려면 JobComponentSystem을 상속받아 System을 구현해야 한다. 이 부분은 다음 예제인 HelloCube_02_IJobProcessComponentData 에서 확인할 수 있다.

ECS는 ConvertToEntity라는 MonoBehaviour를 제공한다. ConvertToEntity는 기존 방식대로 Hierarchy 창에서 만든 GameObject와 그 자식 오브젝트들을 로딩 시점에 Entity와 Component로 변환한다. 현재 ConvertToEntity는 유니티 빌트인(built-in) MonoBehaviour 중 Transform, MeshRenderer를 변환할 수 있다. 변환된 결과물인 Entity와 Component는  Entity Debugger에서 확인할 수 있다. 아래 그림은 기존 MeshRenderer가 RenderMesh Component로 변환돼서 RenderMeshSystemV2에 의해 처리되는 모습이다. Entity Debugger 사용법은 "[Unity][DOTS] Entity Debugger 사용 방법" 포스트를 참고하시길 바란다.

직접 작성한 MonoBehaviour에 IConvertGameObjectToEntity 인터페이스를 구현하면 ConvertToEntity가 기존 MonoBehaviour의 데이터를 Component로 변환해준다. 이 예제에서는 RotationSpeedProxy MonoBehaviour에서 RotationSpeed Component를 Entity에 추가하기 위해 IConvertGameObjectToEntity 인터페이스를 구현했다.

public class RotationSpeedProxy : MonoBehaviour, IConvertGameObjectToEntity
{
  public float DegreesPerSecond;
  public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
  {
    var data = new RotationSpeed { RadiansPerSecond = math.radians(DegreesPerSecond) };
    dstManager.AddComponentData(entity, data);
  }
}

이 예제의 실행 화면은 다음과 같다. 귀찮아서 GIF 파일로 만들지 않고 스크린샷만 찍었는데 매 프레임마다 RotationSpeedSystem이 RotationSpeed 값을 얻어서 큐브를 Y축 기준으로 회전시킨다.

다음 포스트에서는 HelloECS의 두번째 예제인 HelloCube_02_IJobProcessComponentData를 파헤쳐보겠다.

반응형

댓글