ECS官方案例3. IJobChunk

基于Unity2019最新ECS架构开发MMO游戏笔记2

  • 官方案例解析3
    • 3. IJobChunk
    • 小结
      • DOTS 逻辑图表
  • 更新计划
    • 作者的话
  • ECS系列目录
    • ECS官方示例1:ForEach
    • ECS官方案例2:IJobForEach
    • ECS官方案例3:IJobChunk
    • ECS官方案例4:SubScene
    • ECS官方案例5:SpawnFromMonoBehaviour
    • ECS官方案例6:SpawnFromEntity
    • ECS官方案例7:SpawnAndRemove
    • ECS进阶:FixedTimestepWorkaround
    • ECS进阶:Boids
    • ECS进阶:场景切换器
    • ECS进阶:MegaCity0
    • ECS进阶:MegaCity1
    • UnityMMO资源整合&服务器部署
    • UnityMMO选人流程
    • UnityMMO主世界

官方案例解析3

开始之前的准备工作:
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 场景

3. IJobChunk

这个案例演示了基于Jobs的ECS系统如何旋转一对方块儿,与同样使用Jobs系统的案例2不同的是,在循环遍历的时候,前者迭代的是实体,而这个案例迭代的是块(内存块,这个块是被一开始基于相同原型分配好了的,也就是说,如果这20个实体有相同的组件,那么他们会被紧密的安排在一块内存中,从而方便处理器进行操作。这是相对于面向对象的散列内存而言的,在面向对象中要操作内存中的某个对象时,你不得不在整个内存中寻找它,这样会降低读取速度,也不方便批量操作。ECS则会非常紧密地分配实体在内存中的位置,相同的组件会被统一放在块中,读取速度快,也方便批量操作)。下面来一探究竟:

  • Main Camera ……主摄像机
  • Directional Light……光源
  • RotatingCube……旋转的方块
    • ChildCube……子方块

和案例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会跑得更快!

DOTS 逻辑图表

System Burst Jobs Entities 你好!任务交给你快速编译一下? 编译好了,任务交给你安排执行? 不好意思,你们的旋转已经排上日程了! 全体都有,集合,向右看齐,向前看,转起来! 我们不想转,我们要放假! 又转起来了! 为什么会说“又”? 旋转,跳跃 我闭着眼…… System Burst Jobs Entities

流程大体如下:

Data
Schedule
OnUpdate
Entities
Component
System
Burst
Jobs
ForEach

更新计划

Mon 12 Mon 19 Mon 26 1. ForEach 2. IJobForEach 3. IJobChunk 4. SubScene 5. SpawnFromMonoBehaviour 6. SpawnFromEntity 7. SpawnAndRemove 休息 修正更新计划 参加表哥婚礼 进阶:FixedTimestepWorkaround 进阶:BoidExample 进阶:SceneSwitcher 我是休息时间 资源整合 部署服务器 启动流程 登录流程 游戏主世界 待计划 待计划 待计划 待计划 待计划 我是休息时间 待计划 待计划 待计划 待计划 待计划 我是休息时间 读取Excel自动生成Entity 读取Excel自动生成Component 读取数据库自动生成Entity 读取数据库自动生成Component ESC LuaFrameWork Skynet DOTS 官方示例学习笔记 -----休息----- 基于ECS架构开发MMO学习笔记 LuaFrameWork学习笔记 -----休息----- 基于Skynet架构开发服务器学习笔记 制作代码自动生成工具 总结 基于Unity2019最新ECS架构开发MMO游戏笔记

作者的话

AltAlt

如果喜欢我的文章可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证!
如果有技术难题需要讨论,可以加入开发者联盟:566189328(付费群)为您提供有限的技术支持,以及,心灵鸡汤!
当然,不需要技术支持也欢迎加入进来,随时可以请我喝咖啡、茶和果汁!( ̄┰ ̄*)

ECS系列目录

ECS官方示例1:ForEach

ECS官方案例2:IJobForEach

ECS官方案例3:IJobChunk

ECS官方案例4:SubScene

ECS官方案例5:SpawnFromMonoBehaviour

ECS官方案例6:SpawnFromEntity

ECS官方案例7:SpawnAndRemove

ECS进阶:FixedTimestepWorkaround

ECS进阶:Boids

ECS进阶:场景切换器

ECS进阶:MegaCity0

ECS进阶:MegaCity1

UnityMMO资源整合&服务器部署

UnityMMO选人流程

UnityMMO主世界

你可能感兴趣的:(ECS,DOTS)