다른 Entity들을 참조하여 Prefab을 생성합니다.
1. "Scripts/Authoring" 폴더에 "CannonBallAuthoring.cs"라는 이름의 새 C# 소스 파일을 만들고 아래 코드를 작성합니다.
using Unity.Entities;
using Unity.Rendering;
using Unity.Mathematics;
class CannonBallAuthoring : UnityEngine.MonoBehaviour
{
class CannonBallBaker : Baker<CannonBallAuthoring>
{
public override void Bake(CannonBallAuthoring authoring)
{
// 기본적으로 Component는 0으로 초기화됩니다.
// 따라서 이 경우 CannonBall의 Speed 필드는 float3.zero가 됩니다.
AddComponent<CannonBall>();
}
}
}
// 포탄에 대한 동일한 접근 방식으로 Entity를 식별하는 Component를 생성합니다.
// 하지만 이번에는 Speed 필드라는 데이터를 포함하고 있기 때문에 Tag Component(비어 있음)가 아닙니다.
// 즉시 사용되지는 않지만 모션을 구현할 때 관련성이 있게 됩니다.
struct CannonBall : IComponentData
{
public float3 Speed;
}
2. Hierarchy창에서 "SampleScene"을 마우스 오른쪽 버튼으로 클릭하고 GameObject > 3D Object > Sphere를 선택한 다음 새 GameObject의 이름을 "CannonBall"로 지정합니다. 위치를 (0,0,0)으로, 회전을 (0,0,0)으로, 크기를 (0.2,0.2,0.2)로 설정합니다.
3. "CannonBall" GameObject에 "CannonBallAuthoring" 구성요소를 추가합니다.
4. "CannonBall" GameObject에서 "Sphere Collider" 구성요소를 제거합니다.
5. "CannonBall" GameObject를 Project창의 "Prefabs" 폴더로 드래그 앤 드롭으로 Prefab으로 만들어줍니다.
6. "SampleScene"에서 "CannonBall" GameObject(현재 Prefab Instance)를 삭제합니다.
7. "Scripts/Authoring" 폴더에서 "TurretAuthoring.cs" 파일의 내용을 다음과 같이 수정합니다.
using Unity.Entities;
class TurretAuthoring : UnityEngine.MonoBehaviour
{
+ public UnityEngine.GameObject CannonBallPrefab;
+ public UnityEngine.Transform CannonBallSpawn;
class TurretBaker : Baker<TurretAuthoring>
{
public override void Bake(TurretAuthoring authoring)
{
- AddComponent<Turret>();
+ AddComponent(new Turret
+ {
+ // 기본적으로 각 GameObject는 Entity로 바뀝니다.
+ // GameObject(또는 authoring component)가 주어지면 GetEntity는 Entity를 찾습니다.
+ CannonBallPrefab = GetEntity(authoring.CannonBallPrefab),
+ CannonBallSpawn = GetEntity(authoring.CannonBallSpawn)
+ });
}
}
}
struct Turret : IComponentData
{
+ // 이 Entity는 포탄이 스폰되는 포탄의 포문을 참조합니다.
+ public Entity CannonBallSpawn;
+ // 이 Entity는 대포가 발사될 때마다 생성되는 Prefab을 참조합니다.
+ public Entity CannonBallPrefab;
}
8. "Turret" GameObject를 선택하고 "Turret Authoring" Component의 새 필드 "CannonBallPrefab" 및 "CannonBallSpawn"을 Project창에서 "CannonBall" Prefab, Hierarchy창에서 "SpawnPoint" GameObject 각각 드래그 앤 드롭으로 등록해줍니다.
8. "Scripts/Aspects" 폴더에 "TurretAspect.cs"라는 새 C# 소스 파일을 만들고 거기에 아래 코드를 작성합니다.
using Unity.Entities;
using Unity.Mathematics;
using Unity.Rendering;
// Turret 컴포넌트에 직접 접근하는 대신 aspect를 생성합니다.
// Aspects를 사용하면 Component에 액세스하기 위한 사용자 지정 API를 제공할 수 있습니다.
readonly partial struct TurretAspect : IAspect
{
// 이 참조는 Turret Component에 대한 읽기 전용 액세스를 제공합니다.
// 읽기 전용 참조에서 ValueRW(ValueRO 대신)를 사용하려고 하면 오류가 발생합니다.
readonly RefRO<Turret> m_Turret;
// 다음 속성에서 ValueRO의 사용에 유의하십시오.
public Entity CannonBallSpawn => m_Turret.ValueRO.CannonBallSpawn;
public Entity CannonBallPrefab => m_Turret.ValueRO.CannonBallPrefab;
}
Note:
다음 단계에서는 유형이 지정된 Component에 대한 임의 액세스를 제공하는 ComponentLookup<T>를 사용합니다. 이 기능에 대한 자세한 내용은 API Documentation를 확인하십시오.
https://docs.unity3d.com/Packages/com.unity.entities@1.0/api/Unity.Entities.ComponentLookup-1.html
9. "Scripts/Systems" 폴더에 "TurretShootingSystem.cs"라는 새 C# 소스 파일을 만들고 아래 코드를 작성합니다.
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Rendering;
using Unity.Transforms;
[BurstCompile]
partial struct TurretShootingSystem : ISystem
{
// ComponentLookup은 Component에 대한 임의 액세스를 제공합니다(Entity 조회).
// 스폰지점(포문)의 월드 공간 Position과 Rotation을 추출하는 데 사용할 것입니다.
ComponentLookup<WorldTransform> m_WorldTransformLookup;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
// ComponentLookup 구조는 한 번 초기화해야 합니다.
// 이 매개변수는 조회가 읽기 전용인지 또는 쓰기를 허용해야 하는지를 지정합니다.
m_LocalToWorldTransformFromEntity = state.GetComponentLookup<WorldTransform>(true);
}
[BurstCompile]
public void OnDestroy(ref SystemState state)
{
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
// ComponentLookup 구조는 매 프레임마다 업데이트되어야 합니다.
m_WorldTransformLookup.Update(ref state);
// 인스턴스화에 필요한 구조적 변경을 연기하기 위해 EntityCommandBuffer 생성.
var ecbSingleton = SystemAPI.GetSingleton<BeginSimulationEntityCommandBufferSystem.Singleton>();
var ecb = ecbSingleton.CreateCommandBuffer(state.WorldUnmanaged);
// Job instance 생성.
// 생성 지점의 월드 변환을 가져오는 데 필요한 ComponentLookup을 전달합니다.
// 그리고 Job이 쓸 수 있는 엔터티 명령 버퍼입니다.
var turretShootJob = new TurretShoot
{
WorldTransformLookup = m_WorldTransformLookup,
ECB = ecb
};
// Schedule execution in a single thread, and do not block main thread.
turretShootJob.Schedule();
}
}
[BurstCompile]
partial struct TurretShoot : IJobEntity
{
[ReadOnly] public ComponentLookup<LocalToWorldTransform> WorldTransformLookup;
public EntityCommandBuffer ECB;
// TurretAspects 매개변수는 읽기 전용으로 선언하는 "in"입니다.
// "ref"(읽기-쓰기)로 설정해도 이 경우에는 차이가 없지만 잠재적 경쟁 조건이 안전 시스템을 트리거하는 상황에 직면하게 됩니다.
// 따라서 일반적으로 "in"을 가능한 모든 곳에서 사용하는 것이 좋은 원칙입니다.
void Execute(in TurretAspect turret)
{
var instance = ECB.Instantiate(turret.CannonBallPrefab);
var spawnLocalToWorld = WorldTransformLookup[turret.CannonBallSpawn];
var cannonBallTransform = LocalTransform.FromPosition(spawnLocalToWorld.Position);
// 새 인스턴스의 변환을 덮어쓰려고 합니다.
// 스케일을 명시적으로 복사하지 않으면 1로 재설정되고 대형 포탄이 생성됩니다.
cannonBallTransform.Scale = WorldTransformLookup[turret.CannonBallPrefab].Scale;
ECB.SetComponent(instance, cannonBallTransform);
ECB.SetComponent(instance, new CannonBall
{
Speed = spawnLocalToWorld.Forward() * 20.0f
});
}
}
10. 플레이 모드로 들어가면 탱크 뒤에 대포알 흔적이 남는 것을 볼 수 있습니다.
'Unity Entities Tutorial' 카테고리의 다른 글
Unity Entities 1.0.0 Tutorial - Step 6. Spawning many tanks (0) | 2023.01.29 |
---|---|
Unity Entities 1.0.0 Tutorial - Step 5. Cannon ball movement (0) | 2023.01.29 |
Unity Entities 1.0.0 Tutorial - Step 3. Tank movement (0) | 2023.01.28 |
Unity Entities 1.0.0 Tutorial - Step 2. Turret Rotation (0) | 2023.01.28 |
Unity Entities 1.0.0 Tutorial - Step 1. Authoring Scene (0) | 2023.01.28 |