Unity DOTS/ECS Sample Projtect

ECS Sample Project #1 ForEach

개양반 2022. 7. 26.

살펴보기 전에 유니티 ECS에 대한 컨셉을 모르시는 분은 아래의 링크에서 정보를 얻기를 바란다.

[Unity DOTS/Dots Custom Manual] - UNITY DOTS - 유니티의 데이터 지향에 대해 간단하게 알아보자

 

Entites 관련 패키지 설치 방법은 아래 링크를 참고한다.

[Unity DOTS] - Entites 0.51 version 설치


오늘 공부할 내용

샘플프로젝트 1탄에서는 Componet를 만들고 Entity를 생성하고 System으로 Entity를 회전시키는 간단한 로직을 돌리는 간단한 구조를 만들겁니다.

입문 단계의 내용이라 파악하는데 어렵지 않을 것입니다.


Scripts 폴더를 만들고 그 안에 1. ForEcah 폴더를 만듭니다. 

1. ForEach 폴더 안에 System, Componet 폴더를 만들어주세요. 


CompoentData 작성

ComponentData에 대한 상세한 내용은 아래의 링크를 참고한다.

[Unity DOTS/Dots Custom Manual] - UNITY DOTS - ICompoentData 에 대해 알아보자.

 

Component 폴더에 우클릭 > Create > ECS > Runtime Component Type을 클릭합니다. 파일 이름을 RotationSpeed_ForEach로 작성합니다.

1. RotationSpeed_ForEach.cs 작성

using System;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;

[GenerateAuthoringComponent] // Hierarchy 뷰에서 GameObject에 Component를 추가할 수 있게 해준다.
public struct RotationSpeed_ForEach : IComponentData
{
    public float RadiansPerSecond;
}

 


System 작성

Component라는 Data를 만들었으니 이번에는 로직을 작성하는 System을 만들 겁니다. 

Scripts/System 폴더에 우클릭 > Create > ECS > System을 클릭하고 파일 이름을 RotationSpeedSystem_ForEach로 만듭니다. 

1. RotationSpeedSystem_ForEach.cs 작성

using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;

public partial class RotationSpeedSystem_ForEach : SystemBase
{
    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        
        Entities
            .WithName("RotationSpeedSystem_ForEach")
            // 항상 ref 다음에 in 이 있어야한다.
            .ForEach((ref Rotation rotation, in RotationSpeed_ForEach rotationSpeed) => {

            rotation.Value = math.mul(
                    math.normalize(rotation.Value),
                    quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));

        }).ScheduleParallel();
    }
}

#코드 분석

.WithName 은 나도 자세히는 모르겠다. 다만 디버그 용도로 사용되는거다. 

.ForEach()

   > 괄호 안의 Component를 가지는 Entities를 Entity별로 반복문을 돌리는 코드다.

   > ref 는 쓰기를 한다는 의미이고 in 는 읽기만 한다는 의미이다. 항상 ref가 앞에 있어야 한다. 

   > ref와 in 키워드를 입력하는 이유는 ForEach는 멀티스레드에서 동작하므로 경쟁문제가 발생하지 않게 프로그램에게 어떤 데이터를 쓰기로 할 것인지 미리 알려야 한다.

 

.ScheduleParallel(); 은 해당 ForEach를 멀티스레드에서 병렬로 처리한다는 의미이다. Run(메인스레드에서 실행), Schedule(멀티스레드 하나에서 실행)를 대신 입력할 수 있다. 

 

math.mul(A, B): A와 B를 곱한다는 의미이다. math 관련은 Mathf.검색할함수 로 검색하면 해당 기능이 무엇인지 알 수 있다. 

 


Entity 만들기

Cube 두개를 만들고 하나는 자식오브젝트로 만들어서 아래 이미지처럼 포개 놓는다. 

ConvertToEntity 를 활성화한다. 플레이모드가 되면 해당 게임오브젝트를 Entity로 변환시키는 기능이다.

RotationSpeed_ForEach.cs를 컴포넌트로 추가하고 Radians Per Second 값을 입력한다.


테스트하기

플레이모드를 누르면 해당 글의 맨 위 상단의 이미지처럼 Cube가 빙글 빙글 돌 것이다.

Window > DOTS > Archetypes, Hierarchy, Systems를 눌러 창을 열고 확인해본다.

 

DOTS Hierarchy 를 보면 방금 우리가 만든 RotationCube가 보인다. 클릭하면 Inspector 창에서 Componet 리스트를 볼 수 있으며 여기서 우리가 만든 RotationSpeed_ForEach 컴포넌트도 볼수 있다. 

GameObject와 Entity가 한 화면에 같이 있다고 하더라도 둘은 다른 세계에 존재하는 객체들이라 서로 충돌 등이 일어나지 않는다.

다음은 Systems 창을 보면 Update에서 우리가 만든 RotationSpeedSystem_ForEeach가 동작하고 있다는 것을 확인할 수 있다. EntityCount는 해당 시스템에 영향을 받고 있는 Entity의 개수이다.

 

이번에는 Archetypes 창도 살펴본다. 맨 아래 쪽의 Archetype을 클릭하면 우리가 만든 RotationSpeed_ForEach 컴포넌트를 가지고 있는 Arehetype을 확인할 수 있다.

 

마지막으로 Profiler에서 Entities Structural Changes를 보면 해당 프레임에서 Entity가 생성되고 해당 Entity에 Component가 추가된 것을 확인할 수 있다. 

 

Entity Profiler에 대한 내용은 아래 링크를 참고한다.

[Unity DOTS/Dots Custom Manual] - Entity Profiler Modules에 대해 알아보자

 

마지막으로 Scene을 01.ForEach 라는 이름으로 원하는 폴더에 저장한다.

댓글

💲 추천 글