转换你的游戏到DOTS(一)

本文转自Unity Connect博主 雨松MOMO

Unite2019哥本哈根学习笔记之Converting your game to DOTS

将传统开发的游戏模式转成DOTS的方式,DOTS全称(Data Oriented Tech Stack) 面向数据的技术堆栈

image

DOTS能干什么?大家看看下面发射这么密集的子弹,如果是传统GameObject的方式肯定会卡死,然而Dots却非常流畅。 可以在Github上下载这个学习工程 https://github.com/UnityTechnologies/AngryBots_ECS

image

DOTS是什么?

  1. Job System :任务系统

  2. Entity Component System(ECS) :实体组件系统

  3. Burst Compiler :Burst编译器 ,也是LLVM编译器

  4. Project Tiny :Unity基于以上3个构成的H5小游戏解决方案

image

需要注意的是以上任务系统、实体组件系统、Burst编译器各自都是独立的系统可以单独使用,它们的集合称之为DOTS.

image

为什么要在项目中使用DOTS?

image

传统面向对象模式下内存就像下图一样,杂乱无序的排放在内存中。当CPU需要读取某个数据时,就要先从这一堆杂乱无序的内中找到需要的内存,然后将它读取并且移动到L1缓存中。缓存的内存大小是固定的远比内存要小很多,拿进来一个内存到缓存中必然就要移除一个。游戏进行中需要读取的内存多了,如果大量的都无法从缓存中拿到,就要重走内存读取在放入L1缓存的流程,势必效率就很差。称之为Cache miss。

image

Entity Component System(ECS) :实体组件系统 ,做的事情就是将传统游戏对象杂乱无序的组件归类,将相同组件整齐排列在内存中。当我们开始遍历相同组件时并不需要一个个从内存中读取,可以指定一个长度一次性全读进来放入缓存中。

image

ECS中我们以块的形式进行保存,每个块有16K字节,每个块也整齐的排列在一起。

image

接着就轮到Job System出场了,任务系统中会找到自己关心的组件依次遍历它们,执行自己的任务。

image

任务之间是可以并行的,这样我们就可以充分利用CPU的多核心,并行任务了。其实就是多线程,多线程中数据很可能出现竞争的情况,所以传统开发需要程序员手动对某个数据“加锁“ 然而Unity实现了一套更好的方案,开发者可以不用写加解锁的代码,通过提供这样的标签[OnlyRead] [OnlyWrite] 系统会自动处理,并且保证数据不会被竞争改写。原理大概是[OnlyRead] 只读数据线程访问是完全安全的,[OnlyWrite] 可写数据则比较危险,需要做好数据的同步。

image

最后轮到Burst编译器出场了,它会编译Job中的代码提升它的性能。

image

当项目中使用DOTS后应该怎么做?

image

当项目中使用DOTS后应该怎么做? 1.解决一个特定问题

2.绕过技术障碍

3.一点点来

4. 对DOTS目前的限制和DOTS未来的功能有清晰的了解。 说人话的意思就是目前DOTS也还在开发中,大家要时刻关注DOTS最新更新的信息,才能正确的使用DOTS(2019.3目前DOTS已经趋于稳定,但是讲这个PPT的时候DOTS还并不太稳定)

image

DOTS和传统开发确实有些区别,你需要仔细思考你的逻辑和数据。 不过作者说的这个图片梗,作为Chinese确实Get不到,哈哈哈~~

image

重点来了,让我们开始集成DOTS进你的游戏中。

image

假如,我们有3个脚本,PlayerMovementAndLook.cs 负责处理角色的移动、旋转、生命值、EnemyBehaviour.cs负责敌人的移动、生命值、ProjectileBehaviour.cs负责导弹的移动、生命值。

image

这种做法是不太好的,聪明的你仔细想想。

image

3个脚本中、速度、生命值、刚体、被重复了3份,这将直接导致每个脚本都需要将这三个对象保存起来,内存长度会更长,显然缓存命中率不友好。而且毫无复用性可言,如果现在新加一个魔法值比变量,主角、怪物的类中都需要添加这个新变量,代码的维护性更加麻烦。

image

再来看看代码中的方法,由于敌人需要旋转、移动两个功能,但是导弹只需要移动功能,被迫只能将重复的逻辑分别写在两个类中。

image

在来看看敌人和主角的碰撞,依然有部分代码是重复的,被迫还是得写两份。

image

ECS的核心就是将红色部分和黄色部分代码分成两个系统,一个系统负责减血、另一个系统负责处理死亡,这样代码的利用率就非常高。还是上面的代码,如果我们写了减血系统和死亡系统后,如果有一天需要添加一个加血功能,我们并不需要修改减血系统和死亡系统的代码,直接添加一个加血系统就可以,这将大幅度提升代码的利用率。 下面我们打开AngryBots_ECS工程。 我们需要将传统的Prefab制作的子弹变成实体对象,打开子弹Prefab挂载的ProjectileBehaviour.cs 添加IConvertGameObjectToEntity接口。

image

然后将原本写在一起的speed 、lifeTime变量保存在不同的组件MoveForward、MoveSpeed、TimeToLive中,将原本序列化在Prefab面板上的值拷贝进实体组件中。分开保存一方面可以起到组件的复用性,另一方面通过增加缓存的命中率。

image

加载的时候,通过GameObjectConversionUtility将Prefab转换成Entity对象。

image

有了Entity对象后就可以通过EntityManager对它实例化了,并且绑定需要的实体组件。

image

每发射一发子弹时就可以在Entity Debugger窗口中看见实体对象以及实体组件信息了,当选择某个实体组件右侧面板中会显示它的序列化信息。

image

通过设置totalAmout可以同时实例化多个实体,并且在循环中对每个实体组件设置坐标信息。

image

修改了发射频率,6W个子弹毫无压力!

image

接着我们需要添加怪物了,怪物需要始终朝向主角的逻辑。我们来将怪物朝向和旋转放到Job多线程中完成。IJobForEach就是只去遍历保存Translation位置和Rotation旋转的组件,然后在Execute方法中执行怪物的朝向。float3 playerPosition表示主角的坐标,需要外部传进来。

image

在OnUpdate中首先判断主角有没有死,如果没有死亡就开始执行Job任务,Job.Schedule表示异步执行。

image

TurnTowardsPlayerSystem的TurnJob中遍历了同时包含Translation位置和Rotation旋转的组件敌人,但是子弹和主角也包含了这个两个组件,所以有时候我们需要在Job中进行区分。 我们可以创建一个空的组件EnemyTag,绑定给怪物。

image

RequireComponentTag就表示遍历的实体组件,必须前置包含EnemtyTag组件,[BurstCompile]表示开始Burst编译器,加载Job代码的执行效率

image

完美!

image
image

2000多个敌人·实体

image

2.7W颗子弹实体

image

发射子弹的瞬超过60FPS毫无压力!

image

原文链接:https://connect.unity.com/p/zhuan-huan-ni-de-you-xi-dao-dots-yi?app=true (内含PPT)

欢迎戳上方原文链接,下载Unity官方技术社区app,在线技术答疑,发现更多资源干货!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,744评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,505评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,105评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,242评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,269评论 6 389
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,215评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,096评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,939评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,354评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,573评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,745评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,448评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,048评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,683评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,838评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,776评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,652评论 2 354

推荐阅读更多精彩内容