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

  • 官方ECS进阶案例解析
      • 开始之前的准备工作:
    • ECS进阶:FixedTimestepWorkaround
      • 小结
        • 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主世界

官方ECS进阶案例解析

开始之前的准备工作:

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目录下找到Advanced/FixedTimestepWorkaround,并打开FixedTimestepWorkaround场景

ECS进阶:FixedTimestepWorkaround

之前学习的7个HelloCube小案例只是ECS入门,比较简单,现在的进阶篇会复杂一些了:

如上图所示,这个案例采用的双主角模式,让我想起了电影《无双》。这个VariableSpawner可以看成发哥,FixedSpawner可以看成城哥,不要小看城哥了,虽然用了Fixed来修饰,让人误以为一层不变,然而却装配了一个Slider,使其在不同的时间步长上千变万化,这就像我们的大脑,表面上波澜不惊,实则已经波涛汹涌。
跑题了,我们先看VariableSpawner发哥好了,打开发哥生成器的Inspector窗口,我们发现上面挂载了ConvertToEntity脚本。这个ConvertToEntity可以看成是常用组件了,任何游戏对象上挂载就可以在运行的时候自动转化成实体。
我猜在新一代的Unity编辑器中,新建物体的时候,不再需要挂载ConvertToEntity脚本。在右键Create的时候,就会有Entity选项,直接创建实体。或者创建出来的所有东西都是默认以实体创建的,再也没有转化的过程。
届时我们将忽略实体和游戏对象的概念,回归组件式开发,ECS默默在底层运行。
再次跑题,发哥身上除了ConvertToEntity脚本外,还有一个VariableRateSpawnerAuthoring脚本,且看:

    /// <summary>/// 参考案例6. SpawnFromEntity/// </summary>public class VariableRateSpawnerAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs{public GameObject projectilePrefab;public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem){var spawnerData = new VariableRateSpawner{Prefab = conversionSystem.GetPrimaryEntity(projectilePrefab),};dstManager.AddComponentData(entity, spawnerData);}public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs){referencedPrefabs.Add(projectilePrefab);}}

这个脚本和案例6. SpawnFromEntity的实体写法一样,先声明自己的预设,然后将自身转化成实体,最后在System中利用预设实体来不断生成新的实体。

 /// <summary>/// 组件,只负责存储数据/// </summary>public struct VariableRateSpawner : IComponentData{public Entity Prefab;}/// <summary>/// 波动生成系统/// </summary>public class VariableRateSpawnerSystem : ComponentSystem{protected override void OnUpdate(){//遍历所有实体,发送更新命令,在更新命令中为其添加组件,并把数据交给组件储存Entities.ForEach((Entity spawnerEntity, ref VariableRateSpawner spawnerData, ref Translation translation) =>{var spawnTime = Time.timeSinceLevelLoad;var newEntity = PostUpdateCommands.Instantiate(spawnerData.Prefab);PostUpdateCommands.AddComponent(newEntity, new Parent {Value = spawnerEntity});PostUpdateCommands.AddComponent(newEntity, new LocalToParent());PostUpdateCommands.SetComponent(newEntity, new Translation {Value = new float3(0, 0.3f * math.sin(5.0f * spawnTime), 0)});PostUpdateCommands.SetComponent(newEntity, new ProjectileSpawnTime{SpawnTime = spawnTime});});}}

这里把组件和系统合在一起写了,毕竟组件就储存一条信息而已,实在没有必要额外弄一个脚本。
这里学到一个新的功能类PostUpdateCommands,它负责将更新命令发送给处理系统,这些更新命令会按照权重缓存起来,然后在主线程中排队执行。这里使用Instantiate来实例化实体,AddComponent来添加组件,SetComponent来传递数据。
这里值得一体的是System用到的几个组件:

/// <summary>
/// 类似原来的Transform组件
/// </summary>
namespace Unity.Transforms
{/// <summary>/// 父组件,只储存了实体的父实体/// </summary>[Serializable][WriteGroup(typeof(LocalToWorld))]public struct Parent : IComponentData{public Entity Value;}/// <summary>/// 前任父组件,储存上一任父实体/// </summary>[Serializable]public struct PreviousParent : ISystemStateComponentData{public Entity Value;}/// <summary>/// 子实体/// </summary>[Serializable][InternalBufferCapacity(8)][WriteGroup(typeof(ParentScaleInverse))]public struct Child : ISystemStateBufferElementData{public Entity Value;}}/// <summary>/// 发射体的生成时间/// </summary>[Serializable]public struct ProjectileSpawnTime : IComponentData{public float SpawnTime;}/// <summary>/// 相对于父实体的本地坐标/// </summary>[Serializable][WriteGroup(typeof(LocalToWorld))]public struct LocalToParent : IComponentData{public float4x4 Value;public float3 Right => new float3(Value.c0.x, Value.c0.y, Value.c0.z);public float3 Up => new float3(Value.c1.x, Value.c1.y, Value.c1.z);public float3 Forward => new float3(Value.c2.x, Value.c2.y, Value.c2.z);public float3 Position => new float3(Value.c3.x, Value.c3.y, Value.c3.z);}

这几个实体组件,都继承了组件相关的空接口,作用只是为了表明自己是什么样的组件,方便系统在使用时刷选。
在波动生成系统中不断发射出来的动感光波,其实就是ProjectileSpawnTimeAuthoring实体,其本身就是实体了,并不需要转化,只是需要把生成时间数据交给ProjectileSpawnTime 组件保存,这里姑且把两者放到一起:

    /// <summary>/// 发射体的生成时间组件/// </summary>[Serializable]public struct ProjectileSpawnTime : IComponentData{public float SpawnTime;}/// <summary>/// 发射体生成时间设置/// </summary>[RequiresEntityConversion]public class ProjectileSpawnTimeAuthoring : MonoBehaviour, IConvertGameObjectToEntity{public float SpawnTime;public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem){var data = new ProjectileSpawnTime { SpawnTime = SpawnTime };dstManager.AddComponentData(entity, data);}}

剩下一个MoveProjectilesSystem 的脚本:

/// <summary>/// 发射体移动系统,负责将发射体不断向前移动,并在超出寿命后摧毁实体/// </summary>public class MoveProjectilesSystem : JobComponentSystem{[BurstCompile]struct MoveProjectileJob : IJobForEachWithEntity<ProjectileSpawnTime, Translation>{public EntityCommandBuffer.Concurrent Commands;public float TimeSinceLoad;public float ProjectileSpeed;public void Execute(Entity entity, int index, [ReadOnly] ref ProjectileSpawnTime spawnTime, ref Translation translation){float aliveTime = (TimeSinceLoad - spawnTime.SpawnTime);if (aliveTime > 5.0f){Commands.DestroyEntity(index, entity);}translation.Value.x = aliveTime * ProjectileSpeed;}}BeginSimulationEntityCommandBufferSystem m_beginSimEcbSystem;protected override void OnCreate(){m_beginSimEcbSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();}protected override JobHandle OnUpdate(JobHandle inputDependencies){var jobHandle = new MoveProjectileJob(){Commands = m_beginSimEcbSystem.CreateCommandBuffer().ToConcurrent(),TimeSinceLoad = Time.timeSinceLevelLoad,ProjectileSpeed = 5.0f,}.Schedule(this, inputDependencies);m_beginSimEcbSystem.AddJobHandleForProducer(jobHandle);return jobHandle;}}

这个系统类似于奥特曼的动感光波发射器,很简单。
而城哥FixedSpawner和发哥发射动感光波的做法是一样的,只是改了个名字而已,你可以认为他们俩其实是一个人。就像电影《无双》里面的情节一样,发哥是城哥臆想出来的一个人物,发哥干了什么好事坏事,城哥也干了。
城哥与发哥不一样的地方在于,城哥还有一个厉害的姘头FixedTimestepUpdater,这个姘头获取了滑动条Slider的数据,用来改变FixedUpdate的更新速率,然后在FixedUpdate中调用其生成系统的Update,最终达到操纵动感光波发射时间的目的。
姘头并没有实际改变实体的组件数据和发射系统,改变的只是更新时间,例如原来是0.02秒更新一次,通过改变Time.fixedDeltaTime的值,就可以改变FixedUpdate的更新速率,如下图所示:

小结

这里其实有三套ECS,首先是发射体Projectile,它的整个系统都被后者利用;然后是发哥VariableSpawner和城哥FixedSpawner,他们俩都是发射动感光波,也就是不断生成发射体;最后是城哥的姘头FixedTimestepUpdater,姘头其实向我们展示了如何在MonoBehaviour中操作ECS的系统。
Projectile:

ECS Scripts Interface1 Interface2
Entity ProjectileSpawnTimeAuthoring IConvertGameObjectToEntity
Component ProjectileSpawnTime IComponentData
System MoveProjectilesSystem JobComponentSystem

VariableSpawner:

ECS Scripts Interface1 Interface2
Entity VariableRateSpawnerAuthoring IConvertGameObjectToEntity IDeclareReferencedPrefabs
Component VariableRateSpawner IComponentData
System VariableRateSpawnerSystem ComponentSystem

FixedSpawner:

ECS Scripts Interface1 Interface2
Entity FixedRateSpawnerAuthoring IConvertGameObjectToEntity IDeclareReferencedPrefabs
Component FixedRateSpawner IComponentData
System FixedRateSpawnerSystem ComponentSystem

这里值得注意的是城哥和发哥的生成系统继承的是ComponentSystem,而非发射体系统继承的JobComponentSystem,JobComponentSystem利用了Jobs和Burst编译器,ComponentSystem显然并没有,而且可以受姘头的影响。

DOTS 逻辑图表

Spawn流程大体如下:

DeclareReferencedPrefabs
Convert
ConvertGameObjectHierarchy
Execute
Instantiate
SetComponent
Spawner
Prefab
SpawnerEntity
PrefabEntity
CommandBuffer
Entities
DOTS

DOTS系统:

Data
Schedule
OnUpdate
Entities
Component
System
Burst
Jobs
ForEach

无双:

发哥城哥姘头你天生就干这个的!任务交给你了!我不干,我不干!你不干的话,就休想干我!为了干你,我干了!我让你快点干你就快点干!我让你慢点干你就慢点干!好好,都听你的!这个世界!姘头说了算!旋转,跳跃我闭着眼……为了姘头,我什么都可以做!假的,什么都是假的,我也是假的!发哥城哥姘头

我是有多无聊,在这里演示无双的剧情,无双和此案例真的没有任何关联,这一篇笔记纯属臆想。

更新计划

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

作者的话

如果喜欢我的文章可以点赞支持一下,谢谢鼓励!如果有什么疑问可以给我留言,有错漏的地方请批评指证!
如果有技术难题需要讨论,可以加入开发者联盟: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进阶:FixedTimestepWorkaround相关推荐

  1. 阿里云ECS进阶训练营Day1 搭建VuePress

    文章目录 零.Demo地址 一.开通阿里云服务器 1.1 购买服务器 1.1.1 去哪购买? 1.1.2 如何购买? 1.2 配置服务器 1.2.1 需要的信息 1.2.2 配置安全组 二.VuePr ...

  2. ECS进阶Day03:SLB负载均衡实践

    SLB负载均衡实践 云服务器状态确认 负载均衡配置 在 **协议&监听** 页面,输入如下信息,完成后,点击 **下一步** . 负载均衡(Server Load Balancer)是将访问流 ...

  3. 【阿里云ECS进阶训练营】day07基于ECS和NAS搭建个人网盘

    目录 一:背景知识 二:实验步骤 1.连接ECS服务器 2.安装OwnCloud 3.安装Apache服务 4.安装并配置PHP 5.配置OwnCloud 6.挂载NAS服务 一:背景知识 云服务器E ...

  4. 用ECS做HexMap:鼠标点击六边形单元涂色

    基于Unity2019最新ECS架构开发MMO游戏笔记21 准备工作 鼠标触碰六边形单元 鼠标点击位置 更新计划 作者的话 ECS系列目录 ECS官方示例1:ForEach ECS官方案例2:IJob ...

  5. 用ECS做HexMap:利用RenderMesh为六边形涂色

    基于Unity2019最新ECS架构开发MMO游戏笔记18 为六边形涂色 链接相邻单元 颜色混合 更新计划 作者的话 ECS系列目录 ECS官方示例1:ForEach ECS官方案例2:IJobFor ...

  6. 用ECS做HexMap:自动生成地图系统

    基于Unity2019最新ECS架构开发MMO游戏笔记16 自动生成地图系统 AutoCreateMapSystem 神奇的六边形 六边形实体 创建者和创建六边形单元系统 更新计划 作者的话 ECS系 ...

  7. 用ECS做HexMap:六边形单元的颜色混合

    基于Unity2019最新ECS架构开发MMO游戏笔记19 颜色混合 颜色平均化 区域混合 三角化混合区域 边界连接桥 填充间隙 边界合并 更新计划 作者的话 ECS系列目录 ECS官方示例1:For ...

  8. 用ECS做HexMap:重构地图系统

    基于Unity2019最新ECS架构开发MMO游戏笔记20 概述 概念 原型Archetypes 内存块 实体查询EntityQuery 任务Jobs 系统组织 优化地图系统 主世界 六边形单元生成系 ...

  9. 2021第一场 | 阿里云高校计划训练营全面升级!0成本体验云计算入门到进阶

    简介:2021,走进云计算的美妙世界(参加训练营免费获取ACA考试资格) 近年来云计算越来越受到重用,它不再仅仅是开源发烧友们的选择,已经在多方面得到了价值体现. 甚至网上流传一句话:云计算适合零基础 ...

最新文章

  1. JVM的内存区域划分(转)
  2. WebService Software Factory 设计草图
  3. php视频降清晰度,使用FFMPEG降低视频分辨率
  4. python第6天作业
  5. dos2unix,unix2dos
  6. 谷粒商城:06. 前端开发基础知识
  7. java实验十三io_Java语言基础13—IO
  8. Photoshop实例视频教程
  9. 项目实战第二十一讲:平台商品库
  10. linux能远程开机么,Linux下如何实现远程开机
  11. 融资租赁、直租回租傻傻分不清楚
  12. JS实现小方块上下移动
  13. Selective Search(选择性搜索)算法学习
  14. iCoremail企业邮箱移动办公新突破
  15. 基于SSM框架的音乐网站系统设计与实现
  16. CAD中插入外部参照字体会变繁体_CAD快速入门(二十七):外部参照
  17. 晴天小猪历险记之Hill
  18. 导出excel文件 java_java实现导出excel文件
  19. 犀牛插件开发-创建圆-Python-点后周长构建圆-Rhino插件
  20. win7电脑关机出现蓝屏怎么办?解决win7电脑关机蓝屏的方法

热门文章

  1. 安徽计算机省一级考试试题,安徽省计算机一级考试试题
  2. 线性相关系数、卡方检验、互信息
  3. 学习上下界网络流小记
  4. [转载] 机器学习科普文章:“一文读懂机器学习,大数据/自然语言处理/算法全有了”
  5. vue绑定失效的问题(操纵组件不更新)
  6. 热敏电阻与温度传感器检测的好坏
  7. 2018年影响MAC-OS的恶意软件(含APT)汇总报告
  8. OpenContrail 体系(一)
  9. 基于预训练模型的军事领域命名实体识别研究
  10. 自己整理_银行核心系统相关技术知识