Unity DOTS (2)

JJW·2025년 2월 17일
0

Unity

목록 보기
24/34

오늘은 Unity DOTS 2편에서는 DOTS에 대한 간단한 회전과 이동을 구현해보도록 하겠습니다.

Entities Graphics로 Hybrid Renderer가 이관되어씀 ㅇ;


코드

Velocity

using Unity.Entities;
using Unity.Mathematics;

// Velocity 컴포넌트: 엔티티가 매 프레임 이동할 방향과 속도를 나타냅니다.
public struct Velocity : IComponentData
{
    public float3 Value;
}

  • ECS에서 컴포넌트에 역할을 하며 데이터만을 담고 있으며 로직은 포함하지 않습니다.
  • 이 컴포넌트는 엔티티가 이동할 때 필요한 이동 방향과 속도 정보를 저장합니다.

RotationSpeed

using Unity.Entities;
using Unity.Mathematics;

// RotationSpeed 컴포넌트: 엔티티가 초당 얼마나 회전할지를 나타냅니다.
public struct RotationSpeed : IComponentData
{
    public float Value; // 도 단위
}
  • 위 Velocity와 동일한 컴포넌트의 역할을 합니다.
  • 매초 얼마나 회전할 지에 대한 정보를 저장합니다.

MoveSystem

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

[BurstCompile]
partial struct MoveSystem : ISystem
{
    public void OnCreate(ref SystemState state) { }
    public void OnDestroy(ref SystemState state) { }

    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        new MoveJob { DeltaTime = deltaTime }
            .ScheduleParallel();
    }

    [BurstCompile]
    public partial struct MoveJob : IJobEntity
    {
        public float DeltaTime;

        public void Execute(ref LocalTransform localTransform, in Velocity velocity)
        {
            localTransform.Position += velocity.Value * DeltaTime;
        }
    }
}
  • ECS에서 시스템의 역할을 담당합니다. 컴포넌트 데이터를 처리하는 로직을 담고 있습니다.
  • Burst 컴파일러를 사용하여 네이티브 코드 수준으로 최적화하여 빠르게 실행됩니다.

RotateSystem

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

[BurstCompile]
public partial struct RotateSystem : ISystem
{
    public void OnCreate(ref SystemState state) { }
    public void OnDestroy(ref SystemState state) { }

    // 매 프레임 호출되는 업데이트 메서드
    public void OnUpdate(ref SystemState state)
    {
        float deltaTime = SystemAPI.Time.DeltaTime;

        new RotateJob { DeltaTime = deltaTime }
            .ScheduleParallel();
    }

    [BurstCompile]
    public partial struct RotateJob : IJobEntity
    {
        public float DeltaTime;

        public void Execute(ref LocalTransform localTransform, in RotationSpeed rotationSpeed)
        {
            // 이번 프레임 동안 회전할 각도를 라디안으로 변환합니다.
            float angleInRadians = math.radians(rotationSpeed.Value * DeltaTime);

            // 전역 up축(0, 1, 0)을 기준으로 회전할 쿼터니언 생성
            quaternion deltaRotation = quaternion.AxisAngle(math.up(), angleInRadians);

            // 현재 회전에 deltaRotation을 곱하여 업데이트하고, 정규화합니다.
            localTransform.Rotation = math.normalize(math.mul(localTransform.Rotation, deltaRotation));
        }
    }
}
  • 위 MoveSystem과 동일한 시스템의 역할을 담당합니다.

MovementAuthoring

using UnityEngine;
using Unity.Mathematics;

public class MovementAuthoring : MonoBehaviour
{
    [Header("이동 설정")]
    public Vector3 moveDirection = new Vector3(1f, 0f, 0f);
    public float moveSpeed = 1f;

    [Header("회전 설정")]
    public float rotationSpeed = 90f; // 초당 90도 회전
}
  • 해당 엔티티가 이동할 방향이나 속도, 회전 속도에 대해 사용자가 조작할 수 있는 클래스입니다.

MovementBaker

using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;

public class MovementBaker : Baker<MovementAuthoring>
{
    public override void Bake(MovementAuthoring authoring)
    {
        var entity = GetEntity(TransformUsageFlags.Dynamic);

        // Velocity 컴포넌트 추가: 이동 방향과 속도를 설정합니다.
        AddComponent(entity, new Velocity
        {
            Value = (float3)authoring.moveDirection * authoring.moveSpeed
        });

        // RotationSpeed 컴포넌트 추가: 회전 속도를 도 단위로 설정합니다.
        AddComponent(entity, new RotationSpeed
        {
            Value = authoring.rotationSpeed
        });
    }
}
  • Baker를 상속 받아 사용하는 클래스 입니다. 엔티티에 DOTS (Velocity,RotationSpeed) 컴포넌트를 추가합니다.
  • ECS 시스템에서 엔티티를 동작 시키기 위한 필수 클래스라고 볼 수 있습니다.

Unity 사용 방법

  • Hierarchy -> Create -> New Sub Scene -> Empty Scene 으로 새로운 Sub Scene을 생성해줍니다.

➡️ Sub Scene 이란?

  • Unity의 DOTS 워크플로우에서 게임 오브젝트를 엔티티로 변환하는 별도의 씬 컨테이너입니다.
  • 즉 일반 씬과 달리 SubScene에 배치된 게임 오브젝트들은 플레이 모드에 진입할 때 자동으로 엔티티로 변화되어 ECS월드에 로드됩니다.

  • 생성 후 게임 오브젝트를 만들어줍니다.

  • 이 후 해당 오브젝트의 Authoring 컴포넌트를 부착해주고 시작하시면 됩니다.

➡️ 화면에 큐브가 보이지 않는 경우

  • 패키지를 Entities, Burst, Mathematics만 설치하셨다면 엔티티에 대해 큐브에서 그려지지 않을겁니다.
  • 원래는 Hybrid Renderer를 설치해야 보이지만 버전이 업데이트 되면서 Entities Graphics로 대체되었다고 합니다. 해당 Entities Graphics 패키지 설치하시면 정상적으로 큐브가 보입니다.

테스트 영상


왜 Baker 클래스의 용도 ?

  • Baker 클래스는 게임오브젝트에 붙이는 것이 아니라, 변환 프로세스 중에 자동으로 호출됩니다.
  • 위 상황에서는
    SubScene ->
    자식 오브젝트 검사 ->
    Authoring 컴포넌트 확인 ->
    찾은 Authoring 컴포넌트에 대한 Baker 찾기 ->
    Baker 클래스의 Bake() 메서드 호출 ->
    Bake() 메서드에서 Authoring 컴포넌트에 설정된 데이터를 읽어들여 DOTS 컴포넌트 추가
  • 즉 Baker 클래스는 변환 과정에서 누가 이 게임오브젝트를 엔티티로 만들고 어떤 DOTS 컴포넌트를
    추가할 것인가를 결정하는 역할을 합니다.

시스템(Move,Rotate)에서는 어떻게 회전과 이동이 되는지 ?

  • 변화된 엔티티는 ECS 월드에 저장되고 시스템은 자동으로 엔티티 쿼리를 수행하여 해당 컴포넌트를 가진 ㅎ엔티티들을 찾아 처리합니다.
  • Execute 메서드에 선언된 매개변수에 따라 해당 컴포넌트를 가진 모든 엔티티를 대상으로 자동 실행됩니다.

➡️ 만약 NPC와 같이 다양한 상태나 행동을 가진 엔티티를 구현하려면?

  • ECS에서는 이를 관리하기 위해 상태 컴포넌트나 태그 컴포넌트를 사용하여 구분한다고 합니다.

결론

  • ECS는 처음 접근하기에는 기존 사용하는 방식과는 전혀 다르기때문에 많은 학습이 필요할 듯 합니다.
  • Animation이나 Navmesh나 사용해봐야 하겠지만 쉽지 않을 듯한 느낌이 듭니다.
profile
Unity 게임 개발자를 준비하는 취업준비생입니다..

0개의 댓글