Entities - Entity 的创建模式
1、 Unity 下创建游戏对象的过程
- UnityEngine.GameObject是一个C#类,是Unity.Component实例的容器,并且必须有一个TransformComponent,可以组织成父子对象层级。
- UnityEngine.Component也是一个C#类,里边有Update方法和其他方法在引擎的GameLoop时调用,并且可以被多个托管类型对象引用,包括GameObject和其他Component,Asset等
- 托管对象无法使用Burst编译,所以除一些特殊类型外,一般来说无法在Jobs中使用,并且托管对象需要GC回收,所以创建和销毁GameObject和它们的Components开销较高。
- 托管对象无法整体的在内存中打包,对Cache不友好
2、Unity 下创建 Entities 对象的模式
2.1 Authoring 模式创建
- Entity SubScene时一个用于GameObject Baked的场景
- Baking 将编辑器中的GameObject转换为写入Entity Scene的Entity也就是将Auhtoring下的数据转换为运行时数据。每次编辑EntityScene场景中的对象时都会触发Baking,并且是增量Baking.
- Baker用来创建自定义数据,用来将自定义组件数据附加到所属的已经创建的Entity上。
- Baking System用来处理Baker产生的数据输出,它只作用在Entity数据上,而不能作用在托管的Authoring数据上,可以使用Jobs和Burst。这个功能是可选的。
举个例子:
在 SubScene 下有一个 Cube,让他进行旋转,如果要让它旋转,先要将旋转的数据 Bake 在 Entity 对象上:
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;namespace DOTS.DOD
{struct RotateSpeedComonent : IComponentData{public float rotateSpeed;}public class RotateSpeedAuthoring : MonoBehaviour{[Range(0, 360)] public float rotationSpeed = 360f;public class Baker : Baker<RotateSpeedAuthoring>{public override void Bake(RotateSpeedAuthoring authoring){var entity = this.GetEntity(TransformUsageFlags.Dynamic);var data = new RotateSpeedComonent{rotateSpeed = math.radians(authoring.rotationSpeed)};AddComponent<RotateSpeedComonent>(entity);SetComponent<RotateSpeedComonent>(entity, data);}}}
}
然后通过一个 System 来对这个带有这个 Component 的对象进行操作
using System.Collections;
using System.Collections.Generic;
using Unity.Burst;
using Unity.Entities;
using Unity.Transforms;
using UnityEngine;namespace DOTS.DOD
{[BurstCompile]public partial struct CubeRotateSystem: ISystem{[BurstCompile]public void OnCreate(ref SystemState state){Debug.Log("[CubeRotateSystem] Start");}[BurstCompile]public void OnDestroy(ref SystemState state){Debug.Log("[CubeRotateSystem] OnDestroy");}[BurstCompile]public void OnUpdate(ref SystemState state){float deltaTime = SystemAPI.Time.DeltaTime;foreach (var (transform, speed) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotateSpeedComonent>>()){transform.ValueRW = transform.ValueRO.RotateY(speed.ValueRO.rotateSpeed * deltaTime);}}}
}
2.2 Runtime 模式创建
- World是Enitites集合,每个Entity在一个世界中ID是唯一的,但也可能和其他世界的EntityID碰撞,所以通常情况下通过ID查找并不是一个安全的方式。
- EnitityManager用来管理世界的所有Entities,有CreateEntity, DestroyEntity, AddComponent, RemoveComponent, GetComponentData,SetComponentData等接
- Entity是一个整型 Id 与 Version 数据组成的结构体,会与Unity.Entities的Component有映射,Entity之间没有父子关系,id 和 Version 完全一样才是同一个 Entity。
- Unity.Entities.IComponentData是一个C#结构体(或者类),可以被EntitiesID索引,但无法被托管对象引用(一般情况),并且没有任何方法(通常),在内存中紧密排列存储,通过Query访问更高效
- System包括SystemBase与ISystem,SystemBase是托管类,简单,但运行在主线程,不能被burst编译,ISystem是Struct,非托管,可以被编译,相当快,但实现起来会有一点复杂。
// 创建新world
var world = new World( "test" );
// 获取World中的EntityManager
var entityManager=world.EntityManager;
// 创建Entity
Entity entity=entityManager.CreateEntity();
// 为创建的entity绑定Component
entityManager.AddComponent<CubeGeneratorByScript>(entity);
// 获取Component数据副本,并设置相关数据后再设置回对应的Component
var generator = entityManager.GetComponentData<CubeGeneratorByScript>(entity);
generator.cubecount=CubeCount;
entityManager.SetComponentData(entity,cubePrototype);....// System中实例化
var generator =SystemAPl.GetSingleton<CubeGeneratorByScript>();
var cubes = CollectionHelper.CreateNativeArray<Entity>(generator.cubeCount, Allocator.Temp);
state.entityManager.Instantiate(generator.cubeEntityProtoType, cubes);
cubes.Dispose();