본문 바로가기

Unity/DOTS

DOTS 학습을 위한 기초 정리 #17 사용자의 입력을 받아 오브젝트 움직이기(IJobForEach)

반응형

참고 : ECS에서 엔티티를 생성할 줄 알고, 제일 기초인 IJobForEach에 대해 이해하고 있어야 한다.

 

사실 아주 간단하게 처리하였지만 많은 고민을 했었지만 제일 시간을 많이 잡아 먹은건 아래와 같았다.

 

1. 많은 오브젝트에 대해 SIMO를 실현할 수 있을까?

 -> 사실 ECS의 Job 시스템이 이를 처리하는 역할을 한다. 다만 어떤게 더 효율적일까 고민하였다.

2. SharedComponentData를 적용해볼 수 있을까?

 -> 조금만 생각해보면 알 수 있는 것인데, 공유된 컴포넌트 데이터는 변경이 최소화 되어야한다. 실시간 입력같은 행위를 했다간 효율이 뚝 떨어진다.

3. 아직 ECS에서는 없는 기능이 많다. 그 없는 기능 중에 "InputSystem"도 있다.

 -> 어쩌겠는가. 모노비헤비어를 이용해야지

 

생각해보면 별거 아니지만 밤새 문서를 보면서 실습하다보니 간단한 사실을 놓치고 있었다.

 

 

그렇다 기본에 충실하기로 했다. 어차피 복잡한 시스템 자체는 고급 문법에 대한 예제에 진입할 때 해보면된다. 지금은 가능한한 심플하게에 집중한다.

 

그래서 플로우를 이렇게 정했다.

1. 아무 변수도 갖추지 않은 PlayerMovement 컴포넌트 데이터를 정의한다.

 -> 사실 이 마저도 필요 없다. Translation만 이용해도 되기 떄문, 다만 이 예제에서는 원하는 엔티티만 움직이길 바래서  이리 하였다.

2. 이동하길 원하는 오브젝트에 이를 등록한다.

3. PlayerMovement System에서 1회 입력을 처리 후 Job에게 넘겨준다.

4. Job은 1회의 입력을 해당하는 Entity 들에게 적용한다.

 

때론 간단한 것이 명답인 것 같다.

 

using Unity.Entities;

namespace ECS.Labs.InputNmove { 
public struct PlayerMovementComponent : IComponentData
{
 //아무런 변수를 갖고있지 않습니다.
 //단순히 이번 예제에서는 이동할 엔티티를 결정하는 요소로서 작용합니다.
}
}

1. 아무 변수도 갖추지 않은 컴포넌트 데이터를 갖춘다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Entities;

namespace ECS.Labs.InputNmove { 
public class PlayerMovementAuthoring : MonoBehaviour,IDeclareReferencedPrefabs,IConvertGameObjectToEntity
{
    void IConvertGameObjectToEntity.Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    {
            dstManager.AddComponentData(entity, new PlayerMovementComponent());
    }

    void IDeclareReferencedPrefabs.DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    {
        referencedPrefabs.Add(gameObject);
    }

}
}

2. 이동하길 원하는 오브젝트를 엔티티로 등록해준다.

 

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

//사용자의 입력을 받아 작업에 입력하여 오브젝트가 움직일 수 있도록 한다.
namespace ECS.Labs.InputNmove {
    public class PlayerMovementSystem : JobComponentSystem
    {

       struct PlayerMovementJob : IJobForEach<PlayerMovementComponent, Translation>
        {
            public float3 Dir; //이동 방향을 정한다.

            public void Execute([ReadOnly] ref PlayerMovementComponent PMC, [WriteOnly] ref Translation translation)
            {
                //단순히 더하기만 해주면된다.
                translation.Value += Dir;
               
            }
        }

        

        protected override JobHandle OnUpdate(JobHandle inputDeps)
        {
            //주의할 점은 struct로 선언된 Job은 메인스레드에서 호출되는 것이 아니란 것 입니다.
            //Input와 같은 UnityEngine에 포함된 클래스들은 메인스레드에서만 호출될 수 있음을 인지해야합니다.
            //즉, 메인스레드인 이 곳에서 미리 입력 정보를 받아 넘겨줘야 합니다.
            var PlayerMovementJob = new PlayerMovementJob {
                Dir = new float3(Input.GetAxis("Horizontal"), 0,Input.GetAxis("Vertical")) * 3f * Time.deltaTime

            }.Schedule(this, inputDeps);

            return PlayerMovementJob;
        }
    }

}

3. 입력을 받고 Job에게 넘겨준다.

 

InputNmove.zip
0.01MB

 

파일을 남긴다.

반응형