1. Component란?
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/concepts-components.html
Unity의 DOTS (Data-Oriented Technology Stack)에서 ECS(Entity Component System)의 핵심 요소 중 하나
ComponentData
는 ECS에서 “데이터”를 저장하는 구조체
위의 예시에서 Speed, Direction, Position, Renderer가 Component
특징
- 일반적으로 값 타입(struct) 선언
- OOP의 클래스 필드와 비슷한 역할을 하지만,
GameObject
나MonoBehaviour
대신 Entity에 데이터를 부착하는 방식 - Unity의 ECS는 데이터와 로직을 분리하여 성능을 극대화하는 구조이므로,
IComponentData
는 순수 데이터만 포함하는 것이 좋음
사용 예시
- Entity의 위치를 저장하는 PositionComponent를 선언
using Unity.Entities; using Unity.Mathematics; // 위치 정보를 저장하는 컴포넌트 public struct PositionComponent : IComponentData { public float3 Value; }
2. IComponentData를 사용하여 Entity에 데이터 추가
IComponentData
를 사용하려면 엔터티(Entity)에 추가해야 함
사용 예시
MonoBehaviour
에서 ECS Entity로 데이터를 변환하는 Baker를 사용하여 PositionComponent를 Entity에 추가
using Unity.Entities; using UnityEngine; public class PositionAuthoring : MonoBehaviour { public Vector3 Position; // Baker 클래스는 이를 ECS의 PositionComponent로 변환하여 엔터티에 추가 class Baker : Baker<PositionAuthoring> { public override void Bake(PositionAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new PositionComponent { Value = authoring.Position }); } } }
3. IComponentData를 읽고 수정하는 방법
ECS에서는 시스템(System)을 이용하여 데이터를 처리
사용 예시
IComponentData
는ComponentLookup<T>
또는SystemAPI
를 사용해 접근Entities.ForEach
또는IJobEntity
를 사용해 병렬 처리
using Unity.Burst; using Unity.Entities; using Unity.Jobs; using Unity.Mathematics; // BurstCompile을 사용하여 성능 최적화 [BurstCompile] public partial struct MoveSystem : ISystem { public void OnUpdate(ref SystemState state) { // SystemAPI.Query<RefRW<T>>()를 사용하여 컴포넌트에 접근하고 데이터를 수정함 foreach (var position in SystemAPI.Query<RefRW<PositionComponent>>()) { position.ValueRW.Value += new float3(1, 0, 0); // X 방향으로 이동 } } }
4. 여러 종류의 Component
Component
는 여러 다른 유형이 있음
프로젝트에서 데이터를 관리하는 방법에 따라 특정 Component
를 사용하면 애플리케이션 성능을 보다 세밀하게 제어할 수 있음
Component | Description |
---|---|
Unmanaged components | 가장 일반적인 컴포넌트 유형이지만, 특정 유형의 필드만 저장할 수 있음 ( struct 기반의 값 타입(Value Type) 만 저장 가능) |
Managed components | 모든 유형의 필드를 저장할 수 있는 관리형(Managed) 컴포넌트 (가비지 컬렉션(GC) 영향을 받을 수 있어 성능에 주의) |
Shared components | Entity를 컴포넌트 값에 따라 Chunk단위로 그룹화함 동일한 값을 가지는 엔터티들이 같은 메모리 Chunk에 저장되어 쿼리 성능을 향상 |
Cleanup components | Entity가 파괴될 때 정리(Cleanup)가 필요한 경우 유용 Entity가 삭제될 때 Cleanup 컴포넌트를 제외한 모든 컴포넌트가 제거됨 |
Tag components | 데이터를 저장하지 않으며 메모리를 차지하지 않는 특수한 컴포넌트 Entity 쿼리에서 필터링할 때 유용. ( IComponentData 를 빈 struct 으로 선언) |
Buffer components (Dynamic buffer components) | 가변 크기 배열(Resizable Array) 역할을 하는 컴포넌트 예를 들어, 경로 점(Path Points) 목록이나 충돌 이벤트 리스트 등을 저장하는 데 사용됨 |
Chunk components | Entity가 아니라 Chunk 전체에 값을 저장하는 컴포넌트 같은 Chunk에 속한 모든 엔터티가 동일한 값을 공유 |
Enableable components | 런타임 중에 활성화/비활성화할 수 있는 컴포넌트 구조적 변경(Structural Change) 없이 상태를 변경할 수 있어 성능 비용을 절약 가능. |
Singleton components | 월드(World) 내에서 단 하나의 인스턴스만 존재하는 컴포넌트 전역 상태 저장용으로 자주 사용됨 |
Editor에서 Component types
에디터에서 다음 아이콘은 다양한 컴포넌트 유형을 나타냅니다. 이는 관련 Entities windows and Inspectors에 나타납니다.
Icon | Component type |
---|---|
A managed component. | |
A shared component. | |
A tag component. | |
A buffer component. | |
A chunk component. |
Unity는 목록에 없는 구성 요소 유형에 대해 일반적인 구성 요소 아이콘을 사용합니다.
(1) Unmanaged components
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-unmanaged.html
Unmanaged components
는 일반적인 데이터 유형을 저장하는 데 사용하며 아래 유형의 필드를 저장할 수 있음
- Blittable types
bool
true
또는false
값을 가지는 논리형(Boolean) 타입char
단일 문자(Character)를 저장, 일반적으로 UTF-16 코드 단위BlobAssetReference<T>
Blob 데이터 구조에 대한 참조, 대량의 불변(Immmutable) 데이터를 효율적으로 저장하고 공유하는 데 사용Collections.FixedString
고정 크기(Fixed-Size) 문자열 버퍼
가변 크기 문자열인string
대신 GC(가비지 컬렉션) 없이 문자열을 저장할 때 사용Collections.FixedList
고정 크기 리스트(Fixed-Size List), 일반List<T>
대신, 할당 없이 고정된 크기의 배열을 사용하는 리스트 구조.- Fixed array (unsafe context에서만 사용 가능)
- 기타 Blittable 조건을 충족하는 구조체(Structs)
Blittable 타입만 포함하는 다른 struct도 Blittable 타입이 될 수 있음
즉, 모든 필드가 Blittable 타입으로 구성된 struct는 Blittable로 간주됨.
Blittable 타입
Blittable(블리터블)이란, 메모리에서 직접 복사(Copy)할 수 있는 데이터 타입을 의미
쉽게 말해, CPU가 메모리를 변환 없이 그대로 읽고 쓸 수 있는 데이터 타입
ECS(Entity Component System)에서 IComponentData는 Blittable 타입을 요구함
Blittable 타입은 관리되지 않는 네이티브 메모리에서 안전하게 사용할 수 있어 성능이 뛰어남
가비지 컬렉션(GC) 영향을 받지 않아 메모리 효율성이 높아짐
Blittable 타입 CPU가 변환 없이 직접 복사 가능 bool
,char
,int
,float
,double
✅ 기본적인 값 타입(Primitive Type) float2
,float3
,float4
(Unity.Mathematics)✅ SIMD 연산 최적화 가능 BlobAssetReference<T>
✅ Blob 데이터 구조체 FixedString
,FixedList
✅ 고정 크기의 문자열 및 리스트
Non-Blittable 타입 ❌ 직접 복사할 수 없고 변환이 필요함 string
❌ 가변 길이 문자열 (Heap 할당) List<T>
/Dictionary<K, V>
❌ 동적 크기 컨테이너 (Heap 할당) class
(참조 타입)❌ 힙 메모리에 저장되며, 포인터를 가짐 object
❌ 박싱(Boxing) 필요
using Unity.Burst; using Unity.Entities; using Unity.Mathematics; // Blittable한 IComponentData 구조체 정의 public struct MoveSpeed : IComponentData { public float Value; // Blittable 타입(float) 사용 } // 엔터티에 MoveSpeed 컴포넌트를 추가하는 Authoring 스크립트 using UnityEngine; public class MoveSpeedAuthoring : MonoBehaviour { public float speed; class Baker : Baker<MoveSpeedAuthoring> { public override void Bake(MoveSpeedAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new MoveSpeed { Value = authoring.speed }); } } } // MoveSpeed 값을 사용하여 Entity를 이동시키는 시스템 [BurstCompile] // 성능 최적화 public partial struct MoveSystem : ISystem { public void OnUpdate(ref SystemState state) { foreach (var moveSpeed in SystemAPI.Query<RefRW<MoveSpeed>>()) { moveSpeed.ValueRW.Value += 0.1f; // X 방향으로 이동 속도 증가 } } }
(2) Managed Components
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-managed.html
Managed Components(관리되는 컴포넌트)는 어떤 타입의 필드라도 저장할 수 있는 IComponentData
이지만, 성능상 단점이 있음.
class
타입으로 선언하며, GC(가비지 컬렉션)의 영향을 받음- Job System과 Burst 컴파일러에서 사용 불가
- 직렬화(Serialization)를 위해 매개변수가 없는 생성자 필수
특징 | Managed Components | Unmanaged Components |
---|---|---|
저장 가능한 데이터 | 모든 타입 사용 가능 | Blittable 타입만 가능 |
메모리 저장 방식 | 개별 배열(Array) 관리 | ECS의 Chunk에 직접 저장 |
Burst 지원 | ❌ 지원되지 않음 | ✅ 지원됨 |
Job System 사용 가능 여부 | ❌ 불가능 | ✅ 가능 |
GC 영향 | ❌ GC 발생 | ✅ GC 없음 |
직렬화 필요 여부 | ✅ 매개변수 없는 생성자 필수 | ❌ 필요 없음 |
Managed Component 생성 예시
using Unity.Entities; // 클래스(class) 타입으로 Managed Component 생성 public class ExampleManagedComponent : IComponentData { public int Value; // 관리되는 타입(int) 저장 가능 }
Managed Component를 Entity에 추가하는 Authoring 스크립트 예시
using UnityEngine; using Unity.Entities; public class ExampleManagedComponentAuthoring : MonoBehaviour { public int Value; class Baker : Baker<ExampleManagedComponentAuthoring> { public override void Bake(ExampleManagedComponentAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new ExampleManagedComponent { Value = authoring.Value }); } } }
Managed Component를 조회하고 수정하는 시스템 예시
using Unity.Entities; using Unity.Burst; // Managed Component는 Burst를 사용할 수 없음 // [BurstCompile] 사용 불가능 public partial struct ExampleManagedComponentSystem : ISystem { public void OnUpdate(ref SystemState state) { foreach (var managedComponent in SystemAPI.Query<ExampleManagedComponent>()) { // 주의:Managed Component는 RefRW<T>로 접근할 수 없으며, 직접 접근 방식을 사용해야 함. managedComponent.Value += 1; // 값 증가 } } }
외부 리소스를 관리하는 Managed Component (ICloneable & IDisposable)
- Managed Component가 외부(UnityEngine.Object) 리소스를 참조할 경우, 복제 및 제거 시 주의해야 함.
using UnityEngine; using Unity.Entities; using System; // 외부 리소스의 수명 주기를 관리 public class ManagedComponentWithResource : IComponentData, IDisposable, ICloneable { public ParticleSystem ParticleSystem; // Unity Object 참조 // 엔터티가 삭제될 때 ParticleSystem도 파괴되도록 설정 public void Dispose() { UnityEngine.Object.Destroy(ParticleSystem); } // 엔터티를 복제할 때 새로운 ParticleSystem을 생성하도록 설정 public object Clone() { return new ManagedComponentWithResource { ParticleSystem = UnityEngine.Object.Instantiate(ParticleSystem) }; } }
Managed Component를 이용한 최적화
Managed Component는 성능이 낮기 때문에, 가능한 경우 Unmanaged Component를 사용해야 함
그러나, 아래와 같은 상황에서는 Managed Component를 사용할 수밖에 없음
- Unmanaged Component로 표현할 수 없는 데이터 저장 (
string
,List<T>
,class
) - UnityEngine.Object를 직접 참조해야 하는 경우 (
GameObject
,ParticleSystem
) - GC 부하를 감수하고라도 가변 데이터 구조 필요할 때
(3) Shared Components
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-shared.html
Shared Components(공유 컴포넌트)는 같은 값을 가진 Entity들을 같은 Chunk로 그룹화하는 ISharedComponentData
타입
일반 IComponentData
와 다르게, Chunk 단위로 저장되며, 동일한 값의 Entity들은 같은 Chunk에 배치됩니다.
항목 | Shared Components | Unmanaged Components |
---|---|---|
저장 단위 | Chunk 단위 저장 | 개별 Entity별 저장 |
Burst 지원 | ❌ 지원되지 않음 | ✅ 지원됨 |
Job System 사용 가능 여부 | ❌ 불가능 | ✅ 가능 |
GC 영향 | ❌ GC 발생 가능 | ✅ GC 없음 |
직렬화 필요 여부 | ✅ 필요함 | ❌ 필요 없음 |
데이터 변경 시 영향 | 값이 바뀌면 Chunk가 재배치됨 | 구조적 변경 없음 |
Shared Components
는 같은 값을 가진 Entity들이 같은 Chunk에 배치되므로 메모리 캐시 적중률을 높이는 데 유용
그러나, 값을 변경할 경우 Entity가 다른 Chunk로 이동해야 하므로 빈번한 변경이 필요할 경우 적합하지 않음
Managed Components
와 달리, struct
타입으로 선언하지만 내부적으로 class
를 포함할 수 있음
Burst 및 Job System을 사용할 수 없으므로 성능이 중요한 곳에서는 Unmanaged Components
를 사용하는 것이 좋음
Shared Component 생성 예시
using Unity.Entities; // ISharedComponentData를 상속받아 Shared Component 생성 public struct ExampleSharedComponent : ISharedComponentData { public int GroupId; // 같은 GroupId를 가진 엔터티들은 같은 Chunk에 저장됨 }
Shared Component를 Entity에 추가하는 Authoring 스크립트
using UnityEngine; using Unity.Entities; public class ExampleSharedComponentAuthoring : MonoBehaviour { public int groupId; class Baker : Baker<ExampleSharedComponentAuthoring> { public override void Bake(ExampleSharedComponentAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); // AddComponent가 아닌 AddSharedComponent()를 사용해야 함 // 같은 groupId 값을 가진 엔터티들이 같은 Chunk에 배치됨 AddSharedComponent(entity, new ExampleSharedComponent { GroupId = authoring.groupId }); } } }
Shared Component를 조회하는 시스템
using Unity.Entities; using Unity.Burst; // Shared Component는 Burst를 사용할 수 없음 // [BurstCompile] 사용 불가능 public partial struct ExampleSharedComponentSystem : ISystem { public void OnUpdate(ref SystemState state) { foreach (var (sharedComponent, entity) in SystemAPI.Query<ExampleSharedComponent>().WithEntityAccess()) { UnityEngine.Debug.Log($"Entity {entity.Index} has GroupId {sharedComponent.GroupId}"); } } }
Shared Component
는 일반적인 IComponentData
처럼 RefRW<T>
로 접근할 수 없음
대신 직접 값 복사 방식으로 접근해야 함
WithEntityAccess()
를 사용하면 어떤 엔터티가 해당 Shared Component
를 가지고 있는지 확인 가능
Shared Component 값 변경
Shared Components
는 값이 변경되면 새로운 Chunk가 생성되므로, 자주 변경되는 값에는 적합하지 않음.
public partial struct UpdateSharedComponentSystem : ISystem { public void OnUpdate(ref SystemState state) { foreach (var (entity, sharedComponent) in SystemAPI.Query<Entity, ExampleSharedComponent>()) { if (sharedComponent.GroupId == 1) { state.EntityManager.SetSharedComponent(entity, new ExampleSharedComponent { GroupId = 2 }); } } } }
Shared Component를 활용하는 예제
- 렌더링 레이어 그룹화
// Layer 값이 같은 엔터티들을 같은 Chunk에 배치 // 같은 레이어의 엔터티들을 한 번에 처리하여 렌더링 최적화 가능 public struct RenderLayer : ISharedComponentData { public int Layer; }
- AI 행동 그룹화
// StateId 값이 같은 적(AI)들은 같은 Chunk에 배치됨 // 특정 AI 그룹을 한 번에 업데이트할 때 유용 public struct AIState : ISharedComponentData { public int StateId; }
- 팀 구분
using Unity.Entities; // 팀 정보를 저장하는 Shared Component public struct TeamComponent : ISharedComponentData { public int TeamId; // 같은 TeamId를 가진 Entity들은 같은 Chunk에 저장됨 }
using UnityEngine; using Unity.Entities; // 팀을 설정하는 Authoring public class TeamComponentAuthoring : MonoBehaviour { public int teamId; class Baker : Baker<TeamComponentAuthoring> { public override void Bake(TeamComponentAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddSharedComponent(entity, new TeamComponent { TeamId = authoring.teamId }); } } }
using Unity.Entities; using Unity.Burst; using UnityEngine; // Burst 사용 불가능 (Shared Component는 Job System에서 직접 접근 불가) public partial struct TeamSystem : ISystem { public void OnUpdate(ref SystemState state) { foreach (var (teamComponent, entity) in SystemAPI.Query<TeamComponent>().WithEntityAccess()) { // WithEntityAccess()를 사용하면 특정 엔터티가 어느 팀에 속해 있는지 확인 가능 Debug.Log($"Entity {entity.Index} belongs to Team {teamComponent.TeamId}"); } } }
public partial struct TeamFilterSystem : ISystem { public void OnUpdate(ref SystemState state) { // 특정 팀 ID(예: TeamId == 1)를 가진 엔터티들만 가져오기 var query = SystemAPI.QueryBuilder().WithAll<TeamComponent>().Build(); state.EntityManager.SetSharedComponent(query, new TeamComponent { TeamId = 1 }); foreach (var (teamComponent, entity) in SystemAPI.Query<TeamComponent>().WithEntityAccess()) { if (teamComponent.TeamId == 1) { Debug.Log($"Entity {entity.Index} is in Team 1"); } } } }
정리
- 같은 값을 가진 Entity들을 같은 Chunk에 저장하여 메모리 접근 최적화 가능
- 자주 변경되지 않는 데이터에 적합 (예: 렌더링 그룹, AI 상태, 네트워크 동기화 등)
- 값이 변경될 경우 새로운 Chunk로 이동해야 하므로 변경이 잦다면 비효율적
- Burst 및 Job System을 사용할 수 없으므로 성능이 중요한 경우 Unmanaged Component 사용이 더 적합
“자주 변경되지 않는” 데이터를 기준으로 Entity를 그룹화할 때 Shared Component
를 사용
(4) Cleanup components
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-cleanup.html
Cleanup Components는 일반 컴포넌트와 유사하지만, 특정 Entity가 삭제될 때 추가적인 정리 작업을 수행할 수 있도록 설계된 특수한 컴포넌트
이 컴포넌트는 Entity가 삭제될 때 모든 일반 컴포넌트를 제거하고, Entity 자체는 Cleanup Components가 모두 제거될 때까지 남아 있음
Entity가 삭제될 때 추가적인 정리 작업(예: 리소스 해제, 이벤트 처리 등)이 필요한 경우에 유용
- ICleanupComponentData : 각 Entity별로 독립적인 정리 작업을 수행하며, 엔티티가 삭제될 때 개별적으로 동작
- ICleanupSharedComponentData : 여러 Entity가 공유하는 데이터를 정리할 때 사용 (같은 리소스를 여러 Entity가 사용할 때, 리소스를 관리하고 정리하는 역할)
항목 | 설명 |
---|---|
목적 | 엔티티가 삭제될 때 추가적인 정리 작업을 수행하기 위해 사용 |
동작 방식 | 엔티티가 삭제될 때 모든 일반 컴포넌트를 제거하고, Cleanup Components만 남깁니다. 엔티티는 Cleanup Components가 모두 제거될 때까지 존재합니다. |
사용 사례 | – 리소스 해제 – 이벤트 처리 – 네트워크 동기화 정리 – 엔티티 삭제 시 추가 로직 실행 |
Burst 지원 | ✅ 지원됨 |
Job System 사용 가능 여부 | ✅ 가능 |
GC 영향 | ✅ GC 없음 (Unmanaged Components와 동일) |
직렬화 필요 여부 | ❌ 필요 없음 |
Cleanup Components의 동작 원리
- 엔티티 삭제 시 동작:
- 엔티티가 삭제되면 모든 일반 컴포넌트가 제거
- Cleanup Components는 남아 있으며, 엔티티는 여전히 존재
- Cleanup Components 제거:
- Cleanup Components가 모두 제거되면 엔티티가 완전히 삭제
- 정리 작업 수행:
- Cleanup Components를 사용하여 엔티티 삭제 시 필요한 추가 작업(예: 리소스 해제, 이벤트 처리 등)을 수행
Cleanup component 생명주기
// Cleanup 컴포넌트를 포함하는 엔티티를 생성합니다. Entity e = EntityManager.CreateEntity( typeof(Translation), typeof(Rotation), typeof(ExampleCleanup)); // 엔티티를 삭제하려고 시도하지만, 엔티티가 Cleanup 컴포넌트를 가지고 있기 때문에 Unity는 실제로 엔티티를 삭제하지 않습니다. // 대신, Unity는 Translation 및 Rotation 컴포넌트만 제거합니다. EntityManager.DestroyEntity(e); // 엔티티는 여전히 존재하므로, 엔티티를 정상적으로 사용할 수 있음을 보여줍니다. EntityManager.AddComponent<Translation>(e); // 엔티티에서 남아 있는 모든 컴포넌트를 제거합니다. // 마지막 Cleanup 컴포넌트(ExampleCleanup)를 제거하면 엔티티가 자동으로 삭제됩니다. EntityManager.RemoveComponent(e, new ComponentTypeSet(typeof(ExampleCleanup), typeof(Translation))); // 엔티티가 더 이상 존재하지 않음을 보여줍니다. entityExists는 false입니다. bool entityExists = EntityManager.Exists(e);
- Cleanup Components 생성 예시
using Unity.Entities; // ICleanupComponentData를 상속받아 Cleanup Component를 정의 // 엔티티가 삭제될 때 추가적인 정리 작업을 수행하는 데 사용 public struct CleanupComponent : ICleanupComponentData { public int ResourceId; // 정리할 리소스 ID }
- Cleanup Components를 Entity에 추가하는 Authoring 스크립트
using UnityEngine; using Unity.Entities; public class CleanupComponentAuthoring : MonoBehaviour { public int resourceId; class Baker : Baker<CleanupComponentAuthoring> { public override void Bake(CleanupComponentAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.Dynamic); // AddComponent를 사용하여 Cleanup Component를 엔티티에 추가 AddComponent(entity, new CleanupComponent { ResourceId = authoring.resourceId }); } } }
(5) Tag components
https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/components-tag.html
Tag components
는 특별한 컴포넌트 유형으로, 주로 Entity를 분류하거나 특정 상태를 나타내는 데 사용
Tag components
는 데이터를 저장하지 않고, 그 자체로 “표식” 역할
이는 예를 들어 Entity가 특정 범주에 속하는지, 아니면 특정 조건을 만족하는지를 나타내는 데 유용
Tag components
는 Entity의 동작에 대한 부가적인 의미를 제공하기 위해 사용
이 컴포넌트는 상태를 나타내는 단순한 “플래그”로, 해당 컴포넌트가 존재하는지 여부만 확인하면 됩니다.
예를 들어, Enemy
나 Player
와 같은 태그 컴포넌트를 사용하여 Entity가 어떤 종류의 객체인지를 표시할 수 있습니다.
using Unity.Entities; // Tag Component 정의 (데이터를 가지지 않음) public struct PlayerTag : IComponentData { } public struct EnemyTag : IComponentData { }
using Unity.Entities; using Unity.Transforms; using UnityEngine; public struct TagComponentSearchSystem : ISystem { public void OnCreate(ref SystemState state) { } public void OnDestroy(ref SystemState state) { } public void OnUpdate(ref SystemState state) { // PlayerTag를 가진 엔티티를 찾아서 처리 var playerQuery = SystemAPI.QueryBuilder().WithAll<PlayerTag, Translation>().Build(); foreach (var (playerTag, translation) in playerQuery) { // 플레이어 엔티티가 있을 때 처리할 코드 Debug.Log("Player found at position: " + translation.Value); } // EnemyTag를 가진 엔티티를 찾아서 처리 var enemyQuery = SystemAPI.QueryBuilder().WithAll<EnemyTag, Translation>().Build(); foreach (var (enemyTag, translation) in enemyQuery) { // 적 엔티티가 있을 때 처리할 코드 Debug.Log("Enemy found at position: " + translation.Value); } } }
using Unity.Entities; using Unity.Transforms; public class TagComponentSearchSystem : SystemBase { protected override void OnUpdate() { // PlayerTag를 가진 엔티티를 찾아서 처리 Entities.ForEach((in PlayerTag playerTag, in Translation translation) => { // 플레이어 엔티티가 있을 때 처리할 코드 UnityEngine.Debug.Log("Player found at position: " + translation.Value); }).Run(); // EnemyTag를 가진 엔티티를 찾아서 처리 Entities.ForEach((in EnemyTag enemyTag, in Translation translation) => { // 적 엔티티가 있을 때 처리할 코드 UnityEngine.Debug.Log("Enemy found at position: " + translation.Value); }).Run(); } }
핑백: ECS – Component concepts (3) - 어제와 내일의 나 그 사이의 이야기
핑백: ECS – Component concepts (2) - 어제와 내일의 나 그 사이의 이야기