开始之前的准备工作:
0下载Unity编辑器(2019.1.0f1 or 更新的版本),if(已经下载了)continue;
1下载官方案例,打开Git Shell输入:
git clone https://github.com/Unity-Technologies/EntityComponentSystemSamples.git --recurse
or 点击Unity官方ECS示例下载代码
if(已经下载了)continue;
2用Unity Hub打开官方的项目:ECSSamples
3在Assets目录下找到HelloCube/3. IJobChunk ,并打开IJobChunk 场景
这个案例演示了基于Jobs的ECS系统如何旋转一对方块儿,与同样使用Jobs系统的案例2不同的是,在循环遍历的时候,前者迭代的是实体,而这个案例迭代的是块(内存块,这个块是被一开始基于相同原型分配好了的,也就是说,如果这20个实体有相同的组件,那么他们会被紧密的安排在一块内存中,从而方便处理器进行操作。这是相对于面向对象的散列内存而言的,在面向对象中要操作内存中的某个对象时,你不得不在整个内存中寻找它,这样会降低读取速度,也不方便批量操作。ECS则会非常紧密地分配实体在内存中的位置,相同的组件会被统一放在块中,读取速度快,也方便批量操作)。下面来一探究竟:
和案例2一样RotatingCube上同样挂了ConvertToEntity脚本,它将Unity的游戏对象GameObject转化成Entity,从而让游戏运行更加高效,脚本的工作原理已经在上一篇讲过了,此处跳过。
RotatingCube上还挂了另外一个脚本RotationSpeedAuthoring_IJobChunk,下面我们来看一下这个脚本:
[RequiresEntityConversion]
public class RotationSpeedAuthoring_IJobChunk : MonoBehaviour, IConvertGameObjectToEntity
{
public float DegreesPerSecond = 360.0F;
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var data = new RotationSpeed_IJobChunk { RadiansPerSecond = math.radians(DegreesPerSecond) };
dstManager.AddComponentData(entity, data);
}
}
代码和上一篇的脚本RotationSpeedAuthoring_IJobForEach几乎一毛一样,区别在于Chunk关键字上了,我这里略过储存数据的RotationSpeed_IJobChunk脚本不讲,实在没有什么可说的,就储存了一个数据而已:
///
/// 我啥也不干,就放数据
///
[Serializable]
public struct RotationSpeed_IJobChunk : IComponentData
{
public float RadiansPerSecond;
}
这里的IComponentData上次讲过,它就是一个空接口而已,作用只是表明自己是Component的身份,从而让System识别,非常纯粹的一个脚本。这里我们将理解到表明身份的重要性,下面是这个案例的重点脚本RotationSpeedSystem_IJobChunk:
///
/// 按块操作实体系统
///
public class RotationSpeedSystem_IJobChunk : JobComponentSystem
{
EntityQuery m_Group;//查询到特定组件的实体,将其放入这个组中
///
/// 这里根据类型来查询到特定的实体
///
protected override void OnCreate()
{
// Cached access to a set of ComponentData based on a specific query
///typeof(Rotation)=带有Rotation组件的;ComponentType=对应RotationSpeed_IJobChunk组件类型的
/// ReadOnly=只读会加快获取实体的速度,ReadWrite=读写 则相对较慢
m_Group = GetEntityQuery(typeof(Rotation), ComponentType.ReadOnly<RotationSpeed_IJobChunk>());
}
// Use the [BurstCompile] attribute to compile a job with Burst. You may see significant speed ups, so try it!
[BurstCompile]//同样使用Burst编译器来加速,区别是使用了块接口:IJobChunk
struct RotationSpeedJob : IJobChunk
{
public float DeltaTime;
///
/// 原型块组件类型=Rotation
///
public ArchetypeChunkComponentType<Rotation> RotationType;
///
/// 只读 原型块组件类型=RotationSpeed_IJobChunk
///
[ReadOnly] public ArchetypeChunkComponentType<RotationSpeed_IJobChunk> RotationSpeedType;
///
/// 找出满足条件的实体来执行
///
/// <原型块/param>
/// 块索引
/// 第一个实体索引
public void Execute(ArchetypeChunk chunk, int chunkIndex, int firstEntityIndex)
{
var chunkRotations = chunk.GetNativeArray(RotationType);
var chunkRotationSpeeds = chunk.GetNativeArray(RotationSpeedType);
for (var i = 0; i < chunk.Count; i++)
{
var rotation = chunkRotations[i];
var rotationSpeed = chunkRotationSpeeds[i];
// Rotate something about its up vector at the speed given by RotationSpeed_IJobChunk.
chunkRotations[i] = new Rotation
{
Value = math.mul(math.normalize(rotation.Value),
quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * DeltaTime))
};
}
}
}
// OnUpdate runs on the main thread.
///
/// 这个方法在主线程上运行
///
/// 输入依赖
///
protected override JobHandle OnUpdate(JobHandle inputDependencies)
{
// Explicitly declare: 声明
// - Read-Write access to Rotation 读写的方式访问旋转
// - Read-Only access to RotationSpeed_IJobChunk 只读的方式访问旋转速度
var rotationType = GetArchetypeChunkComponentType<Rotation>();
var rotationSpeedType = GetArchetypeChunkComponentType<RotationSpeed_IJobChunk>(true);
var job = new RotationSpeedJob()
{
RotationType = rotationType,
RotationSpeedType = rotationSpeedType,
DeltaTime = Time.deltaTime
};
return job.Schedule(m_Group, inputDependencies);
}
}
思路是明确的,一个案例比之前一个更快,切更有目的性!
这就是代码的优化迭代!
我们来对比案例二:
ECS | Scripts | Inherit |
---|---|---|
Entity | RotationSpeedAuthoring_IJobForEach | IConvertGameObjectToEntity |
Component | RotationSpeed_IJobForEach | IComponentData |
System | RotationSpeedSystem_IJobForEach | JobComponentSystem |
和案例三:
ECS | Scripts | Inherit |
---|---|---|
Entity | RotationSpeedAuthoring_IJobChunk | IConvertGameObjectToEntity |
Component | RotationSpeed_IJobChunk | IComponentData |
System | RotationSpeedSystem_IJobChunk | JobComponentSystem |
变化不大,System都利用了Jobs和Burst编译器,Chunk会跑得更快!
流程大体如下:
如果喜欢我的文章可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证!
如果有技术难题需要讨论,可以加入开发者联盟:566189328(付费群)为您提供有限的技术支持,以及,心灵鸡汤!
当然,不需要技术支持也欢迎加入进来,随时可以请我喝咖啡、茶和果汁!( ̄┰ ̄*)