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中的一种面向数据的设计思想,理解内核还是很重要的,后续再加上其他内容