Entity的理解
Entity作为一种对CPU的Cache友好的编码方式,是DOTS中重要的编码流程与思想。需要程序员由OOP的思想转为DOD的思想,即:面向数据的编码方式。
Unity的ECS:
Entity:只是一个代表,用于快速查找数据等
Component:只有数据的Struct,无法被引用(特殊手法可以),大量相同的Component并排在内存中,可以提高Cache的命中率,以及Burst编译器生成SIMD命令提高性能。
System:用于处理Component的类,包含真正的处理逻辑,有一套自己的生命周期管理。可以遍历筛选出自己需要的Component进行处理。在System中可以结合JOBS来进一步提升性能。
一、Entity是什么?
Entity在DOTS的ECS系统中,只是作为一个包装的概念,看下官方文档的解释。
简单理解就是一个Struct,里面包含两个数据,Index以及Version。Index指向Entity在EntityWorld中的编号,Version则是版本号。因为Index会被复用,所以销毁一个Enity,又创建一个的时候,这个Index会被复用,然后通过Version就可以判定一个唯一的Enity了。
二、Entity的创建
1.Authoring模式
Authoring模式,在subScene中创建一个GameObject,Unity会隐式使用一个叫做Bake的过程,把托管的GameObject转换成对应的Entity(以及附带的各种内部Component)。
我们还需要用自定义的Component,这个时候,可以在对应的Monobehaviour脚本中,添加一个继承Baker的类,来转换你想要的Enity,以及动态添加自定义的Component
struct RotateSpeed : IComponentData{public float rotateSpeed;}public class RotateSpeedAuthoring : MonoBehaviour{[Range(0, 360)]public float rotateSpeed = 360.0f;public class Baker : Baker<RotateSpeedAuthoring>{public override void Bake(RotateSpeedAuthoring authoring){var entity = GetEntity(TransformUsageFlags.Dynamic);var data = new RotateSpeed{rotateSpeed = math.radians(authoring.rotateSpeed)};AddComponent(entity,data);}}}
以上代码就是将一个挂载了RotateSpeedAuthoring脚本的GameObject转换成一个Entity的过程。同时还为这个Entity添加了RotateSpeed的自定义Component
注意:Baker是增量bake的。
/// <summary>/// Called in the baking process to bake the authoring component/// </summary>/// <remarks>/// This method will be called for every instance of TAuthoringType in order to bake that instance./// </remarks>/// <param name="authoring">The authoring component to bake</param>public abstract void Bake(TAuthoringType authoring);
备注:BakingSystem:用于控制Bake产出的Entity行为,相当于bake转换Entity时,可以通过这个类来控制对应的Entity产出,比如:可以给某些entity转换时,都加上一个Component数据。避免一个个在各个Bake里面手动加代码。
2.Runtime模式
World:Entity的集合,每个Entity在一个World中ID唯一,但是Unity中可以有多个World,各个World中的Entity可能有相同的ID。
EntityManager:管理他自身所在World中的所有Entity,可以创建,销毁Entity,也可以增、删、刷新Entity中的Component数据
ComponentData与Entity具有一定的映射关系,同时ComponentData因为是Struct类型,所以无法(一般情况下)在托管对象进行引用从而管理里面的数据。
创建Entity流程:
1.创建World或者获取一个World;2.拿到World中的EnityManager,创建一个Entity;3.,同时也可以通过这个EntityManager来管理Entity上的Component;4.通过创建的Entity来获取EntityAcheType来实例化更多同类型Entity;5.对应的System就可以实现对这些Entity进行逻辑处理了。
备注:Entity之间没有父子之类的关系,但是可以通过Parent组件来体现这种关系。
var generator = SystemAPI.GetSingleton<CubeGeneratorByPrefab>();var cubes = CollectionHelper.CreateNativeArray<Entity>(generator.cubeCount, Allocator.Temp);state.EntityManager.Instantiate(generator.cubeEntityProtoType, cubes);int count = 0;foreach (var cube in cubes){state.EntityManager.AddComponentData<RotateAndMoveSpeed>(cube, new RotateAndMoveSpeed{rotateSpeed = count*math.radians(60.0f),moveSpeed = count});var position = new float3((count - generator.cubeCount * 0.5f) * 1.2f, 0, 0);var transform = SystemAPI.GetComponentRW<LocalTransform>(cube);transform.ValueRW.Position = position;count++;}cubes.Dispose();
其中:SystemAPI.GetSingleton可以用来获取唯一的组件如上图的:CubeGeneratorByPrefab
总结
ECS作为DOTS中的一种面向数据的设计思想,理解内核还是很重要的,后续再加上其他内容