关于Unity 2018的实体组件系统(ECS)二

孙广东  2018.5.20git

 

关于Unity 2018的实体组件系统(通用名称ECS)二github

 

将介绍如何在Unity上使用实体组件系统(一般称为ECS)。json

此次的内容是Unity提供的ECS API的基本用法,一个小应用程序和并行化。编辑器

 

它不包括与Unity的GameObject / Component的合做,以及实际使用。ide

 

 

获取可使用ECS的编辑器优化

Unity2018 和以后的版本均可以!this

 

您能够从 https://github.com/Unity-Technologies/EntityComponentSystemSamples 下载官方的一个Demo。操作系统

 

以后,下载与您本身的操做系统匹配的编辑器并安装它。.net

 

 

建立一个可使用ECS的项目翻译

我将建立一个项目,但我没法使用ECS。

要启用ECS,须要两件事。

 

  • 使使用 .NET 4.x
  • 重写 manifest.json

正常启动Unity并打开 Edit> PlayerSettings> PlayerSettings。

以后,将Scripting Runtime Version脚本运行时版本更改成Stable (.net 4.x)。

 

 

接下来是重写manifest.json。

因为在项目的Root文件夹/ Packages中有一个名为manifest.json的文件,所以咱们将按照https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/TwoStickShooter/Pure/Packages/manifest.json 与此处相同的方式重写内容。

 

准备工做完成。

 

最小的ECS项目

首先,尝试尽量地构建最有意义的功能。

此次要组织的功能就是这样

  • 统计每一个帧

 

一、 没有使用 ECS的代码 :

首先我会试着用MonoBehaviour来组织它。这是一个很是简单的代码。

编写完成后,您能够将Counter组件添加到适当的GameObject中。

using UnityEngine;

public class Counter : MonoBehaviour{ public int count;

void Update () { count++; }}

 

接下来,让咱们对应于ECS。有三件事要作

它是什么?麻烦? ECS就是这样

 

  • CountData 计数的值
  • CountSystem 实际计数
  • ECSMain 实体

ComponentDatas.cs

using Unity.Entities;

 

// 实体

public struct CountData : IComponentData

{

public int count;

}

 

CountSystem.cs

using Unity.Entities;

 

public class CountSystem : ComponentSystem

{

// System所需的ComponentData列表

struct Group

{

public int Length;

public ComponentDataArray<CountData> countData;

}

 

[Inject] Group group; // 注入请求的ComponentData

 

// 调用每一帧

protected override void OnUpdate()

{

for(int i=0; i<group.Length; i++)

{

var countData = group.countData[i];

countData.count++;

group.countData[i] = countData;

}

}

}

ECSMain.cs

using UnityEngine;

using Unity.Entities;

 

public class ECSMain : MonoBehaviour

{

void Start ()

{

// 获取EntityManager

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

 

// 定义实体的原型

var sampleArchetype = entityManager.CreateArchetype(typeof(CountData));

 

// 实际上基于原型生成实体

entityManager.CreateEntity(sampleArchetype);

}

}

 

 

 

 

以后,若是您将ECSMain附加到适当的对象并Play,则第一步完成。

在Play期间,打开Window > EntityDebugger,当它从Systems列表中找到CountSystem时,它会变白,而且若是实体存在 。

 

 

 

若是没有实体,那么您有可能在没有CountData的状况下建立实体,或者您没有首先建立实体。另外,若是您没有系统,则建立ComponentSystem的代码有问题。

 

 

 

一点评论

看如下内容。

对于每一个角色的 ECS 是以下所示。

 

 

那么,首先ComponentData,这里重要的是struct(结构)并继承IComponentData。

将它用做ComponentData时,这两个都是必需的。

 

 

建立实体ECSMain是一种建立实体的翻译,但它从MonoBehaviour事件中调用它,等等。

 

正如你在注释中看到的那样,

 

  • 获取EntityManager
  • 建立实体原型
  • 根据原型信息建立实体

这是一个流程。

 

彷佛没有必要考虑ComponentData存储在原型中的顺序以及建立它的时机。只有内在的东西才是重要的。

 

 

 

最后一个关于CountSystem做为ComponentSystem。这是一个两部分组成。

 

  • 组的定义
  • 处理内容

首先是Group的定义和实际injection的代码。

 

ComponentDataArray包含(指向)请求组件的指针,而Length包含具备请求ComponentData的实体数目。

 

在 [Inject] 中,自动注入对请求组的引用。

 

 

 

 

 

下半部分代码... OnUpdate() 部分只需添加数字。请注意,组的内容是一个结构,所以您不能直接分配它。

 

 

增长系统的例子

接下来我会尝试增长系统

 

若是计数器超出范围,则该过程的内容就像删除同样。

功能解释忽略了更多的效率。

 

 

ECS基本上由相似皮带输送机的流程任务组成,系统处理一些ComponentData并将其传递给下一个系统....

 

所以,“添加计数器并在计数器超出范围时移除计数器”

 

  • 称为“实体包括计数器”的容器
  • 向系统添加计数器
  • 系统 检查计数器并丢弃它,若是它是无用的

 

 

 

为了实现这一点,我会再增长一些。

 

  • Common ComponentData 获取范围
  • 计数超出范围时删除实体的 系统
  • CountSystem之间的依赖关系

 

代码在这里:

ComponentDatas.cs

using Unity.Entities;

 

// 実体

public struct CountData : IComponentData

{

public int count;

}

 

[System.Serializable]

public struct RangeData : ISharedComponentData

{

public int min, max;

}

ECSMain.cs

using UnityEngine;

using Unity.Entities;

using Unity.Collections;

 

public class ECSMain : MonoBehaviour

{

[SerializeField] RangeData range;

 

EntityArchetype sampleArchetype;

 

void Start()

{

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

sampleArchetype = entityManager.CreateArchetype(typeof(CountData), typeof(RangeData));

}

 

private void Update()

{

if(Input.anyKey)

{

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

var entity = entityManager.CreateEntity(sampleArchetype);

entityManager.SetSharedComponentData<RangeData>(entity, range);

}

}

}

RangeSystem.cs

using Unity.Entities;

using Unity.Collections;

using Unity.Jobs;

 

[UpdateAfter(typeof(CountSystem))]

public class RangeSystem : ComponentSystem

{

struct Group

{

public int Length;

public EntityArray entities;

[ReadOnly] public ComponentDataArray<CountData> countData;

[ReadOnly] public SharedComponentDataArray<RangeData> rangeData;

}

 

[Inject] Group group;

 

protected override void OnUpdate()

{

for (int i=0; i<group.Length; i++)

{

var range = group.rangeData[i];

var data = group.countData[i];

if ( data.count > range.max || data.count < range.min )

{

PostUpdateCommands.DestroyEntity(group.entities[i]);

}

}

}

}

 

解释一下代码:

 

首先,咱们添加了RangeData,它是用于范围判断的ComponentData。

可是,因为该“范围信息”在大多数数据中具备相同的值,所以使用对多个实体公用的IShardComponentData。

还添加了Serializable属性,以即可以使用Inspector进行设置。

 

 

 

ECSMain添加了这个CountData。

 

(1) 首先,RangeData显示在Inspector上,以便编辑,(2) RangeData做为类型添加到原型中,(3) RangeData设置在建立的Entity中。

 

以后,咱们经过按下按钮来改变实体的类型。

 

 

最后是系统。

虽然它是一个系统,当它超出范围时删除实体......固然,它有必要得到“范围”。所以,在(2) 中,RangeData包含在组中。

 

在③中,使用DestroyEntity删除实体。

 

这里值得注意的是Update ① 和 [ReadOnly] 。这两个用法大体相同,彷佛若是[ReadOnly]存在,它将在使用[WriteOnly]等的系统以后被调用。一样,若是有UpdateAfter,它将在指定的系统以后被调用。

 

 

 

 

 

 

并行化

在这段时间结束时,尝试并行化ECS处理。目标是增长计数。

 

当处理负载至关长或者有不少对象时,并行化多是一个好结果。

CountSystem.cs

using Unity.Entities;

using Unity.Jobs;

 

public class CountSystem : JobComponentSystem

{

AddCounterJob job;

 

protected override void OnCreateManager(int capacity)

{

base.OnCreateManager(capacity);

// 作一份工做

job = new AddCounterJob();

}

 

// 发布工做

protected override JobHandle OnUpdate(JobHandle inputDeps)

{

return job.Schedule(this, 64, inputDeps);

}

 

[ComputeJobOptimization] // Burst编译器的优化属性

struct AddCounterJob : IJobProcessComponentData<CountData> //请求ComponentData

{

public void Execute(ref CountData data)

{

data.count++;

}

}

}

 

下图是处理大约6000个实体的时间比较。因为它将并行和burst结合在一块儿,因此存在很大的差别。

 

 

 

可是,有不少地方不能使用并行,由于这种数据处理和行为在可用数据和行为方面受到限制。在某些状况下,若是您使用C# Job System,您可能能够作更多...

相关文章
相关标签/搜索