当前位置:   article > 正文

Unity ECS编程官方文档选译——ECS In Detail(1)_unity ecs官方文档

unity ecs官方文档

一、Entity,Component与内存布局

 

1,Entity

 

Entity(本质上)是一个ID。你可以把它当作一种超级轻量级的GameObject,默认情况下它甚至没有名字。


您可以在运行时从Entity动态添加或删除Component。Entity ID是可靠的。 实际上,如果你想要存储对另一个Component或Entity的引用,使用Entity ID去存储也是唯一可靠的方式。

 

译注:作者说把Entity当作GameObject有一定的误导性,实际上它和GameObject非常不同。Entity本质是数据(就是Component)分类分组以后得到的一个ID而已,我们用这个ID去操作一组相同类型的数据。

 

2,IComponentData

 

传统的Unity Component(包括MonoBehaviour)是面向对象的类,所以说它包含了数据和定义行为的方法。IComponentData是纯粹的ECS类型的组件,意味着他不定义行为,只包含数据。IComponentData是结构体(struct)而非类(class),所以他们进行值拷贝而不是引用拷贝。

 

你一般需要使用如下模式去修改IComponentData的值:

  1. var transform = group.transform[index]; //读取
  2. transform.heading = playerInput.move; //修改
  3. transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed;
  4. group.transform[index] = transform; //写入

 

注意:ECS很快就要基于C#7.0编译了,如果使用C#7.0的 ref return特性就使额外的内存分配变得没有必要了。

 

IComponentData结构体不能包含对托管对象的引用,因为组件里所有的数据都存在于简单的没有垃圾回收的块(chunk)里。

 

译注:IComponentData作为struct直接在栈里分配,它不像class一样分配在托管堆里,不进行垃圾回收,是实现所谓“连续紧凑的内存布局”的好结构。
纯粹ECS下,Component名为Component,但要抛弃过去的认识,实际上它就只是纯粹的数据而已,与逻辑完全无关。

 

3,EntityArchetype

 

一个EntityArchetype是一个ComponentType构成的独特数组。EntityManager使用它来对所有使用相同ComponentType的Entity进行分组。

 

  1. // 使用typeof关键字从一组Component中创建一个EntityArchetype
  2. EntityArchetype archetype = EntityManager.CreateArchetype(typeof(MyComponentData), typeof(MySharedComponent));
  3. // 相同功能的API,但是更轻巧也更高效
  4. EntityArchetype archetype = EntityManager.CreateArchetype(ComponentType.Create<MyComponentData>(), ComponentType.Create<MySharedComponent>());
  5. // 从EntityArchetype创建一个Entity
  6. var entity = EntityManager.CreateEntity(archetype);
  7. // 方便起见,隐式地创建一个EntityArchetype
  8. var entity = EntityManager.CreateEntity(typeof(MyComponentData), typeof(MySharedComponent));

 

4,EntityManager

 

EntityManager拥有EntityData、EntityArchetypes、 SharedComponentData和ComponentGroup。


你在EntityManager 里面可以找到API来创造Entity、检查一个Entity是否存活、实例化Entity以及添加或移除组件。

 

使用EntityManager对Entity进行操作实例如下:

  1. // 创建一个不包含Component的Entity
  2. var entity = EntityManager.CreateEntity();
  3. // 在运行时向Entity动态添加Component
  4. EntityManager.AddComponent(entity, new MyComponentData());
  5. // 获取Entity的ComponentData
  6. MyComponentData myData = EntityManager.GetComponentData<MyComponentData>(entity);
  7. // 设置Entity的ComponentData
  8. EntityManager.SetComponentData(entity, myData);
  9. // 在运行时从Entity动态移除Component
  10. EntityManager.RemoveComponent<MyComponentData>(entity);
  11. // 是否存在拥有指定Component的Entity?
  12. bool has = EntityManager.HasComponent<MyComponentData>(entity);
  13. // Entity是否alive?
  14. bool has = EntityManager.Exists(entity);
  15. // 实例化Entity
  16. var instance = EntityManager.Instantiate(entity);
  17. // 销毁这个实例
  18. EntityManager.DestroyEntity(instance);

 

EntityManager也提供了批处理的API来一次创建或销毁多个Entity,这些API显然更快,出于性能考虑,我们应该尽可能地使用这些API。

  1. // 实例化500个Entity并它们的ID写到instances这个数组
  2. var instances = new NativeArray<Entity>(500, Allocator.Temp);
  3. EntityManager.Instantiate(entity, instances);
  4. // 销毁这500个实例
  5. EntityManager.DestroyEntity(instances);

 

5,内存块(chunk)的实现详情

 

每个Entity的ComponentData都储存于我们称之为内存块(chunk)的地方。ComponentData以流的方式布局,意味着:所有类型为A的Component,都被紧紧地包裹在一个数组里面。紧跟着的是包裹着B类型Component的数组,再紧跟着的是包裹着C类型Component的数组,以此类推。


每个内存块总是链接到一个具体的EntityArchetype上,从而在一个块里的所有Entity都遵循完全相同的内存布局。在遍历Component时,块内Component的内存访问总是完全线性的,并没有浪费加载到缓存行中。这点必须要保证。


ComponentDataArray本质上是一个迭代器,它能够遍历全部与所需Component兼容的EntityArchetype。就访问EntityArchetype来说,就是去遍历所有与它相匹配的块;就访问块来说,就是去遍历所有在那个块里的Entity。

 

译注:原文<ComponentDataArray is essentially an iterator over all EntityArchetypes compatible with the set of required components; for each EntityArchetype iterating over all chunks compatible with it and for each chunk iterating over all Entities in that chunk.>。

 

一旦一个块里的Entity都被访问过了,我们就找到下一个匹配的块,然后访问那里面的那些Entity。


当Entity被销毁了,我们就把别的Entity移到它的位置去,然后再更新Entity表。
如上文所说,要对Entity的线性布局做出有力保证,所以这么做是必需的。Component数据在内存中移动的代码也经过了高度优化。

 

译注:Unity官方ECS样例: Unity-Technologies/EntityComponentSystemSamples

所以,Entity、Component只相当于纯粹的数据,一点逻辑处理都没有。写逻辑处理的部分的是System和Job。第二部分的“System、Job和多线程处理”的部分会进行阐述,这一部分有点复杂,很多地方我也没有搞懂作者在说些什么(假如作者自己知道自己在说什么的话),为了避免误人子弟,这一部分的译文过几天再出。。。

来自https://zhuanlan.zhihu.com/p/36672148

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/105619?site
推荐阅读
相关标签
  

闽ICP备14008679号