环境: Unity:6000.2.10f1 Entities:1.4.3
参考:https://github.com/Unity-Technologies/EntityComponentSystemSamples
实例化预设Prefab 在DOTS中,实例化预设的Prefab通常通过Authoring组件和Baker来实现。以下是一个炮塔射击系统的示例,展示了如何在Baker中引用Prefab实体,并在Job中实例化它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class TurretRotationAuthoring : MonoBehaviour { public GameObject bulletPrefab; class TurretRotationBaker : Baker<TurretRotationAuthoring> { public override void Bake (TurretRotationAuthoring authoring ) { var entity = GetEntity(TransformUsageFlags.Dynamic); AddComponent(entity, new TurretShootComponent() { BulletPrefab = GetEntity(authoring.bulletPrefab, TransformUsageFlags.Dynamic) }); } } } public struct TurretShootComponent : IComponentData{ public Entity BulletPrefab; } public void OnUpdate (ref SystemState state ) { var ecb = SystemAPI .GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>() .CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter(); state.Dependency = new SpawnJob { ECB = ecb }.ScheduleParallel(state.Dependency); } [BurstCompile ] public partial struct TurretShootJob : IJobEntity{ public float DeltaTime; public EntityCommandBuffer.ParallelWriter ECB; void Execute ([EntityIndexInQuery] int sortKey, ref LocalTransform transform, ref TurretShootComponent shootComponent, Entity entity ) { Entity bullet = ECB.Instantiate(sortKey, shootComponent.BulletPrefab); ECB.SetComponent(sortKey, bullet, component); } }
实体/组件操作 主线程中:
获取实体单例:
1 2 3 4 Entity _entity; SystemAPI.TryGetSingletonEntity<CharacterAgentComponent>(out _entity); Entity e = SystemAPI.GetSingletonEntity<MyComponent>();
获取实体上的组件:
1 LocalTransform playerTransform = SystemAPI.GetComponent<LocalTransform>(_entity);
根据组件获取实体:
1 2 3 4 5 EntityQuery query = SystemAPI.QueryBuilder() .WithAll<MyComponent>() .Build(); using var entities = query.ToEntityArray(Allocator.Temp);
或者使用foreach:1 2 3 4 5 6 foreach (var (comp, entity) in SystemAPI.Query<RefRO<MyComponent>>() .WithEntityAccess()) { }
Job/子线程中
ECB(Entity Command Buffer)是ECS的事务系统(执行失败会报错,但不影响其他命令)。在Job中提交命令,在帧末统一执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 void OnUpdate (ref SystemState state ) { var ecb = SystemAPI .GetSingleton<EndSimulationEntityCommandBufferSystem.Singleton>() .CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter(); new BulletMoveJob { DeltaTime = SystemAPI.Time.DeltaTime }.ScheduleParallel(); } [BurstCompile ] public partial struct BulletMoveJob : IJobEntity{ public float DeltaTime; public EntityCommandBuffer.ParallelWriter ECB; void Execute ([EntityIndexInQuery] int sortKey, ref LocalTransform transform, ref BulletMoveComponent moveComponent, Entity entity ) { Entity bullet = ECB.Instantiate(sortKey, shoot.BulletPrefab); ECB.SetComponent(sortKey, bullet, component); ECB.AddComponent(sortKey, entity, new Health { Value = 100 }); ECB.RemoveComponent<DeadTag>(sortKey, entity); ECB.DestroyEntity(sortKey, entity); } }
注意:ECB.AddComponent添加组件后,不能马上读到这个组件,需要等到下一帧。ECB是ECS的事务系统:Job里只提交命令,命令在当前帧的ECB System Playback时统一执行,Playback之后World立即改变,但只有在Playback之后运行的系统(通常是下一帧)才能观察到这些变化。
获取实体上的组件1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 void OnUpdate (ref SystemState state ) { var ltLookup = SystemAPI.GetComponentLookup<LocalTransform>(true ); new TurretShootJob { ltLookup = SystemAPI.GetComponentLookup<LocalTransform>(true ) }.ScheduleParallel(); } [BurstCompile ] public partial struct TurretShootJob : IJobEntity{ [ReadOnly ] public ComponentLookup<LocalTransform> ltLookup; void Execute ([ChunkIndexInQuery] int sortKey, ref TurretShootComponent shoot, in LocalToWorld muzzleLtw ) { if (ltLookup.HasComponent(entity)) { LocalTransform lt = ltLookup[entity]; } } }