오늘은 Unity DOTS 2편에서는 DOTS에 대한 간단한 회전과 이동을 구현해보도록 하겠습니다.
Entities Graphics로 Hybrid Renderer가 이관되어씀 ㅇ;
using Unity.Entities;
using Unity.Mathematics;
// Velocity 컴포넌트: 엔티티가 매 프레임 이동할 방향과 속도를 나타냅니다.
public struct Velocity : IComponentData
{
public float3 Value;
}
- ECS에서 컴포넌트에 역할을 하며 데이터만을 담고 있으며 로직은 포함하지 않습니다.
- 이 컴포넌트는 엔티티가 이동할 때 필요한 이동 방향과 속도 정보를 저장합니다.
using Unity.Entities;
using Unity.Mathematics;
// RotationSpeed 컴포넌트: 엔티티가 초당 얼마나 회전할지를 나타냅니다.
public struct RotationSpeed : IComponentData
{
public float Value; // 도 단위
}
- 위 Velocity와 동일한 컴포넌트의 역할을 합니다.
- 매초 얼마나 회전할 지에 대한 정보를 저장합니다.
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 컴파일러를 사용하여 네이티브 코드 수준으로 최적화하여 빠르게 실행됩니다.
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과 동일한 시스템의 역할을 담당합니다.
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도 회전
}
- 해당 엔티티가 이동할 방향이나 속도, 회전 속도에 대해 사용자가 조작할 수 있는 클래스입니다.
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 시스템에서 엔티티를 동작 시키기 위한 필수 클래스라고 볼 수 있습니다.

- 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 클래스는 게임오브젝트에 붙이는 것이 아니라, 변환 프로세스 중에 자동으로 호출됩니다.
- 위 상황에서는
SubScene ->
자식 오브젝트 검사 ->
Authoring 컴포넌트 확인 ->
찾은 Authoring 컴포넌트에 대한 Baker 찾기 ->
Baker 클래스의 Bake() 메서드 호출 ->
Bake() 메서드에서 Authoring 컴포넌트에 설정된 데이터를 읽어들여 DOTS 컴포넌트 추가
- 즉 Baker 클래스는 변환 과정에서 누가 이 게임오브젝트를 엔티티로 만들고 어떤 DOTS 컴포넌트를
추가할 것인가를 결정하는 역할을 합니다.
- 변화된 엔티티는 ECS 월드에 저장되고 시스템은 자동으로 엔티티 쿼리를 수행하여 해당 컴포넌트를 가진 ㅎ엔티티들을 찾아 처리합니다.
- Execute 메서드에 선언된 매개변수에 따라 해당 컴포넌트를 가진 모든 엔티티를 대상으로 자동 실행됩니다.
➡️ 만약 NPC와 같이 다양한 상태나 행동을 가진 엔티티를 구현하려면?
- ECS에서는 이를 관리하기 위해 상태 컴포넌트나 태그 컴포넌트를 사용하여 구분한다고 합니다.
- ECS는 처음 접근하기에는 기존 사용하는 방식과는 전혀 다르기때문에 많은 학습이 필요할 듯 합니다.
- Animation이나 Navmesh나 사용해봐야 하겠지만 쉽지 않을 듯한 느낌이 듭니다.