오늘부터는DOTS를 배워보려고 한다.
무거운 기능들을 지금의 개발환경에서 원하는 부분만 따로 적용할 수 있다는 사실에 배워보고싶어서
오늘부터 시작해보려고 한다.
1.ECS 의 기본 이해
- ECS는 DOTS의 핵심이며, 게임 객체를 관리하는 새로운방식이다.기존 GameObject와 MonoBehaviour의 방식과달리 데이터와 행동 을 완전히 분리해서 관리한다.
- 기본적으로 Entity, Component, System이어떻게 서로연결되는지 이해하는것이 필요하다.
- Entity : 단순히 식별자 역할만하는 객체이다. 데이터나 기능도 없고 컴포넌트를 모아주는 역할을 한다.
- Component : 데이터만 보유하는 구조체 이다. 속도, 위치 등의 데이터만 해당한다. 동작(메서드) x
- System : 컴포넌트를조작하는로직이다. 예를 들면 모든 Entity의 위치를 업데이트 하거나 충돌을 체크하는 등의 행동 로직을 담당한다.
아직 이해가 잘 안된다.
실제게임에서 사용할 수 있는 예제를 만들어보자.
목표
여러 적캐릭터가 플레이어를향해 자동으로 이동하는 시스템 구현
DOTS의 ECS를 사용해 적 캐릭터의 위치를 효율적으로 업데이트 하기
예제 설명
1. 플레이어는 기존 GameObject로 설정, 적은 DOTS의 Entity로 다룬다.
2. 적 캐릭터들은 매 프레임 플레이어의 위치를 확인하고 플레이어방향으로 이동한다.
준비할것
Entities패키지 설치
시작하기
1. 적 컴포넌트 정의하기 (아까 얘기했듯 데이터를 들고있다.)
using Unity.Entities;
public struct ChaseComponent : IComponentData
{
public float speed;
}
2. 적 생성 시스템 (아까 얘기했듯 로직이 들어있다.)
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
using UnityEngine;
public class EnemySpawnerSystem : MonoBehaviour
{
public GameObject enemyPrefab;
public int enemyCount = 10;
private EntityManager entityManager;
void Start()
{
entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
// 엔티티 아키타입 생성
EntityArchetype archetype = entityManager.CreateArchetype(
typeof(Translation), // 위치
typeof(Rotation), // 회전
typeof(ChaseComponent) // 추격 컴포넌트
);
// 적 엔티티 생성
for (int i = 0; i < enemyCount; i++)
{
Entity enemyEntity = entityManager.CreateEntity(archetype);
entityManager.SetComponentData(enemyEntity, new Translation { Value = new float3(i * 2, 0, 0) });
entityManager.SetComponentData(enemyEntity, new ChaseComponent { speed = UnityEngine.Random.Range(1f, 3f) });
}
}
}
3. 추격 시스템 (로직)
using Unity.Entities;
using Unity.Transforms;
using Unity.Mathematics;
using UnityEngine;
public class ChaseSystem : SystemBase
{
protected override void OnUpdate()
{
// 플레이어 위치를 가져옵니다. (여기서는 플레이어 GameObject가 있어야 함)
float3 playerPosition = GameObject.FindWithTag("Player").transform.position;
// 모든 적 엔티티에 대해 이동 로직 실행
Entities.ForEach((ref Translation translation, in ChaseComponent chase) =>
{
// 적이 플레이어를 향해 이동하는 벡터 계산
float3 direction = math.normalize(playerPosition - translation.Value);
translation.Value += direction * chase.speed * Time.DeltaTime;
}).ScheduleParallel(); // 병렬 처리로 성능 최적화
}
}
재밌다..