网上已经有比较多的DOTS的资料了,这里就简单介绍一下。DOTS,Data-Oriented Technology Stack ( 数据导向型技术栈)的缩写,是Unity退出的面向多线程编程的解决方案 ,其包含了 C# Job System、Entity Component System (ECS) 、Burst等组件组成。这里推荐一个up做的比较系统的笔记来参考一下(https://www.yuque.com/dev666/rxitsg/chtnhs 感谢这位叫做dev666的博主的分享)里面有相当多的干货资料,对DOTS的实现原理、具体使用、API等都有详细的分析,感谢!
我主要还是看了ECS这一块的东西,感觉比较适合开发包含大量重复性且着色器渲染一致模型的应用场景。ECS没有了状态,只有大量的实体(Entity),实体上的挂载的组件(Component),对组件进行操作的系统(System)。通过对实体添加对应的组件来标记实体可以具有的能力,然后通过系统来过滤指定一个或一组组件,间接赋予实体能力,已经跟传统的面向对象不太一样了。附上个参考图

参照着这个项目做出了demo(https://www.yuque.com/dev666/rxitsg/lfdqbo),这是个纯ECS的小游戏项目,场景不需要挂载任何脚本直接创建空场景就能够运行,下面附上开发环境的配置情况
Unity 2019.3.0f6
Enities preview.33-0.0.12
Hybrid Render preview.13-0.0.1
Mathematics preview.20 0.0.12
Universal RP 7.1.8
在配置好开发环境后,unity可能会报以下错误
这是引用的插件找不了RenderPipeline的相关引用方法,并不影响程序使用,可以直接屏蔽掉引用了RenderPipeline.beginCameraRendering的代码。(估计是ECS需要RenderPipeline但现版本的unity并没有提供相关的类库)
附上工程的下载路径
链接:https://pan.baidu.com/s/1v3BqFsVU2Zza4FTDDZF-tA
提取码:0hnc
工程的运行截图
这个demo可以说是纯ECS实现的,没有Mono的代码,通过给实体添加组件并利用系统实现能力的形式,实现了UI显示,输入控制,球体创建与下落、碰撞检测、得分判断等等功能。
再说明下这个工程需要注意的地方
项目是使用了自定义的渲染管线,所以我直接下载了URP插件(想省事的话可以直接下载Core RP Library)需要手动创建Render Pipeline Asset文件并拖拽到project settings的Graphic上
直接创建空场景不需要Camera直接运行就能看到项目的运行,同时要把Game窗口设置成Free Aspect,因为里面的UI就是手动创建的,并不是使用UGUI
一个项目最好只包含一个ECS的项目,因为ECS大多数类都不需要挂载到场景中,很可能会重复定义引起混淆。
下面是关于ECS使用的个人总结:
1.Component可以置空当作TAG来用
public struct Player : IComponentData { }
public struct Ball : IComponentData { }
2.在方法头中申明[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
即使不挂载场景也可以在运行时触发
3.EntityManager的获取方法
a.通过World.Active.EntityManager获取
b.继承ComponentSystem的类 可以直接调用EntityManager
4.
获取单例
GetSingleton<Game>() 获取单例的Component
GetSingletonEntity<Player>() 获取单例的Entity
设置单例
SetSingleton<Game>(game)
5.
获取Entity上的Component
Position playerPosition=EntityManager.GetComponentData<Position>(player);
增加Entity上的Component
EntityManager.AddComponent(visibleReadyUIQuery, typeof(Disabled));
删除Entity上的Component
EntityManager.RemoveComponent(invisibleReadyUIQuery, typeof(Disabled));
以上三个可以对Entity、EntityQuery进行操作
6.筛选Query 一般在OnCreate中初始化
private EntityQuery query;
protected override void OnCreate()
{
query=GetEntityQuery(new EntityQueryDesc
{
All=new[]{},//必须同时都有的Component组
None=new[]{},//只要有了就会被排除的Component组
Any=new[]{} //只要存在任意一个Component就符合的组
}
);
}
All、None、Any都是ComponetType[]类型 ,则元素都是ComponentType.ReadOnly(Component)
GetEntityQuery也可以直接使用,不需要All None Any
GetEntityQuery(ComponentType.ReadOnly<GameOverUI>(), ComponentType.ReadOnly<Disabled>());
7.在ComponentSystem中的update里删除Entity
PostUpdateCommands.DestroyEntity(entities[i])
8.遍历query的结果操作
using (NativeArray<ArchetypeChunk> chunks = this.query.CreateArchetypeChunkArray(Allocator.TempJob))
{
foreach (ArchetypeChunk chunk in chunks)
{
}
}
9.获取chunk里面的Enity或者Component
ArchetypeChunkEntityType entityType = GetArchetypeChunkEntityType();
NativeArray<Entity> entities = chunk.GetNativeArray(entityType);
ArchetypeChunkComponentType<Position> positionType = GetArchetypeChunkComponentType<Position>();
NativeArray<Position> positions = chunk.GetNativeArray(positionType);
10.ComponentSystem的执行顺序在类头申明
在指定的组里面运行
[UpdateInGroup(typeof(InitializationSystemGroup))] 初始化
[UpdateInGroup(typeof(PresentationSystemGroup))] 逻辑与运算
[UpdateInGroup(typeof(SimulationSystemGroup))] 图形处理
自定义组
public class InputHandlingSystemGroup : ComponentSystemGroup { }
自定义组并规定它的执行顺序
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateBefore(typeof(UpdateSystemGroup))]
public class InputHandlingSystemGroup : ComponentSystemGroup { }
待补充