最近随着守望先锋制作组在gdc上发布的一个关于ecs的talk,ecs这个架构算是得到了一定的曝光度。

在这之前,github上就一直有一个C#的ecs框架名为Entitas,截止现在已经有1300+的star了,同时提供了和unity整合的方法(对,你可以不用unity,直接把它当C#的库来做其他的东西)
地址: https://github.com/sschmid/Entitas-CSharp
同时还有一个gitter:https://gitter.im/sschmid/Entitas-CSharp 很多entitas的开发者会在上面进行相关的问答,推荐时不时看两眼。

还有云风大大对守望先锋的talk的解析,http://blog.codingnow.com/2017/06/overwatch_ecs.html 推荐在用Entitas一段时间,熟悉ECS之后再看,写的非常棒。

要是对ecs有一定理解的人(一系列很不错的文章在 http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/ ,主要是讲ecs相对oop的优点的,将OOP在MMORPG开发中的弊端批判了一番),可以知道ecs的优点之一在于缓存命中率极高。因为设计良好时,同一类component在内存中是连续排列的。但是出于种种原因,C#难以写出一个足够flexible的框架来实现这一优点。而Entitas使用了生成代码的方法,将这一优点保留了下来,同时也会生成非常友好的API以供调用。

目前Entitas的版本在0.42.3,算是还没有完全成型,但是满足我这种小打小闹写代码是完全可以的。

提到Entitas,就不得不说一下Unity中GameObject-Component的设计。有人认为Unity中这种架构也是ECS架构,但事实上

  1. Unity中的Component都是一个完整的类,缓存不友好。
  2. Unity中的Component包含逻辑。当然你也可以要求出程序员不能在Component里写Update等函数。
  3. Unity中你没办法去获取所有“有ComponentA和ComponentB的所有GameObject”,而在ECS中这是非常必要的。

总的来说,Unity中的架构,更多的是OOP中的“组合优于继承”这一思想的实践,而不是真正的ECS。

回到Entitas上来。Entitas初学者普遍存在的一个问题是Entitas如何和Untiy交互,因为它们的Entity和GameObject并不存在任何实质上的联系。(你把Entitas的代码拿到Unity外面,完全可以运行,如果你没有用Unity的API的话)

这里先推荐一篇他们自己的talk:https://www.youtube.com/watch?v=lNTaC-JWmdI ,如果能看懂的话那这个问题基本上就解决了。

这里再简单的说一下我的思路。一般来说,我倾向于理解Unity作为一个“展示”的工具。所有游戏的逻辑都在Entitas中运行。

如果我要一个Entitas中的Entity在Unity中显示的话,我会添加一个ViewComponent,包含一个GameObject字段,表示它在Untiy中对应的GameObject。

然后添加一个ViewPositionUpdateSystem,它对有ViewComponent和PositionComponent的Entity感兴趣,会在PositionComponent改变时,将ViewComponent中的View也改变位置,此时Unity中你看到的GameObject的位置也就跟着改变了。

这里题外话一点,在一般的ECS介绍文章中,会从类似“物理系统只关心有PhysicsComponent的Entity,渲染系统只关心有RenderComponent的Entity“类似的话开始。在这里,我们也做了类似的事情。只不过我们的“渲染系统”的渲染工作要简单得多,只需要把Unity里的GameObject的位置挪一挪就行了。

再说说物理系统。如果你心大的话,完全可以去找一个第三方库跟Entitas直接接轨,但是用Unity的物理系统也是可以的。关键点和上面一样,将Unity视作一个工具。

首先,既然你用Unity的物理系统,那你想要的Entity肯定得有个ViewCompoennt,然后他的GameObject上有你配置好的碰撞体等。接着你可以在它的GameObject上添加脚本,在OnTriggerEnter等物理相关的函数中通知Entitas发生了物理碰撞。你可以写一个CollisionComponent,其中保存碰撞的信息,在OnTriggerEnter中填写它添加到Entity上去;也可以不添加到Entity上,而是直接放在Contexts中等着感兴趣的人去处理它(你可以添加到一个全局Component的List里,也可以直接新建一个Entity放那儿,都行)。

这其中比较细节的地方是在OnTriggerEnter中填写碰撞信息。有人可能发现了,我们在Entitas的Entity中在ViewComponent里保存GameObject的索引,但是我们在OnTriggerEnter中,我们并不能反过来获得Entity的索引。其实道理是一样的,我们可以写一个MonoBehaviour,其中有一个Entity字段;在你将一个GameObject用ViewCompoent添加到Entity上时,同时给这个GameObject也添加这个Monobehaviour,写上Entity的索引就行了。

因为这个需求实在太常见了,Entitas里内置了一个方法,将Entity和GameObject链接起来。在命名空间Entitas.Unity中提供了GameObject的扩展方法Link,调用该方法的效果跟上一段所说相同,会添加一个叫EntityLink的MonoBehaviour,然后就可以通过这个MonoBehaviour获取到它链接的Entity了。

另外如果有任何问题的话欢迎回复或者私信讨论,本人对ECS也处于不断学习理解的状态,希望可以共同进步

Unity下的ECS框架 Entitas简介的更多相关文章

  1. Unity下的开发框架--适应web和微端游戏异步资源请求的框架

    一.   内容简介: 1.   框架对Web与微端游戏特性的支持: Web和微端游戏最重要的特性是,资源是持续从服务器上即时下载下来的.而保证体验流畅的关键就是保证资源下载分散到持续的体验过程中,并保 ...

  2. 理解ECS的概念和Unity中的ECS设计

    组合优于继承 ecs的概念很早就有了,最初的主要目的应该还是为了改善设计. e-c-s三者都有其意义,e-c是组合优于继承,主要用以改善oo的继承耦合过重以及多继承菱形问题. oop常见设计里,每个g ...

  3. 从零开始写一个武侠冒险游戏-0-开发框架Codea简介

    从零开始写一个武侠冒险游戏-0-开发框架Codea简介 作者:FreeBlues 修订记录 2016.06.21 初稿完成. 2016.08.03 增加对 XCode 项目文件的说明. 概述 本游戏全 ...

  4. android hook 框架 libinject2 简介、编译、运行

    Android so注入-libinject2 简介.编译.运行 Android so注入-libinject2  如何实现so注入 Android so注入-Libinject 如何实现so注入 A ...

  5. 出售一套Unity + Lua热更新框架代码

    出售一套Unity + Lua的客户端框架代码,功能有资源管理.网络通信.配置文件解析.热更新.文件读写.Lua加密揭秘.UI框架.打包工具.编辑器工具等,已经在多个实际项目(已上线)中使用.代码优雅 ...

  6. 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)

    1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...

  7. Debian下安装Firefox与flash简介

    Debian下安装Firefox与flash简介 由于Debian在Firefox的版权上出现了问题,导致官方发布的Debian系统不能使用默认的Firefox浏览器,最后官方重编的Firefox改名 ...

  8. Net Core下多种ORM框架特性及性能对比

    在.NET Framework下有许多ORM框架,最著名的无外乎是Entity Framework,它拥有悠久的历史以及便捷的语法,在占有率上一路领先.但随着Dapper的出现,它的地位受到了威胁,本 ...

  9. windows环境下安装yaf框架

    windows环境下安装yaf框架 在windows下安装yaf框架 准备工作: php环境(过程略,wamp,xampp,phpstudy都行,php版本大于5.3) git工具(需要从github ...

随机推荐

  1. iOS- 网络访问两种常用方式【GET & POST】实现的几个主要步骤

    1.前言 上次,在博客里谈谈了[GET & POST]的区别,这次准备主要是分享一下自己对[GET & POST]的理解和实现的主要步骤. 在这就不多废话了,直接进主题,有什么不足的欢 ...

  2. .net 内置对象之Session对象和Session的过期时间

    QQ:827969653 有需要的朋友可以下载Session类:SessionHelper类 http://technet.microsoft.com/zh-cn/library/system.web ...

  3. 基于gulp的前端自动化开发构建

    就前端的发展而言会越来越朝着后端的标准化靠近,后端的工程化以及模块化都很成熟.基于这样一个思路,开始探索如何优化目前的开发流程.而使用的工具就是gulp. 个人觉得gulp比较webpack更为简单实 ...

  4. delphi 取得数据集某字段值的六种方法

    //取name字段的示例   edit1.Text:=ADOquery1.Fields[2].AsString;   //取得数据表的第二个字段的值 edit2.Text:=ADOquery1.Fie ...

  5. 第52天:offset家族、scroll家族和client家族的区别

    一.offset家族 1.offsetWidth offsetHeight offsetLeft offsetTop offsetParent共同组成了offset家族,用来获取元素尺寸. offse ...

  6. 第28天:js-Tab栏切换封装函数

    一.input.value所有值都是string 二.变量和属性var index=10;//变量var arr=[];//数组arr.index=20;//index为自定义属性,只能在arr下使用 ...

  7. BZOJ 1076 奖励关(状压期望DP)

    当前得分期望=(上一轮得分期望+这一轮得分)/m dp[i,j]:第i轮拿的物品方案为j的最优得分期望 如果我们正着去做,会出现从不合法状态(比如前i个根本无法达到j这种方案),所以从后向前推 如果当 ...

  8. BZOJ4710 JSOI2011分特产(容斥原理+组合数学)

    显然可以容斥去掉每人都不为空的限制.每种物品分配方式独立,各自算一个可重组合乘起来即可. #include<iostream> #include<cstdio> #includ ...

  9. java 注解使用笔记

    一.语法 注解也属于一种类型 public @interface MyTestAnnotation { } 用@interface描述 根据情况可以应用于包.类型.构造方法.方法.成员变量.参数及本地 ...

  10. [国家集训队]最长双回文串 manacher

    ---题面--- 题解: 首先有一个直观的想法,如果我们可以求出对于位置i的最长后缀回文串和最长前缀回文串,那么我们枚举分界点然后合并前缀和后缀不就可以得到答案了么? 所以我们的目标就是求出这两个数列 ...