Unity3D Entitas 入门篇02 当然是HelloWorld

笨木头  2017-09-1 20:54   Unity3D   阅读(505)   0条评论
转载请注明,原文地址:http://www.benmutou.com/archives/2431
文章来源:笨木头与游戏开发
要说学习新的东西,有什么能比得上一个HelloWorld呢?
一个HelloWorld还学不会,那就来两个。

1. Entity(实体)、Component(组件)、System(系统)间的关系

如果你觉得想尽快看到HelloWorld,那就直接从第2步开始,然后再回来看这一步吧。
这里简单介绍ECS三者之间的关系。

 

Entity,即实体,显然,它是一个实质的带有功能的对象,但它又不仅限于角色、怪物这些实体。
因为,在Entitas中,就连鼠标点击产生的事件也作为实体。

 

组件就是一些零散的功能点,如:坐标、武器、攻击力等。
实体就是这些组件的载体,把部分组件组合起来。

 

比如,我有以下的组件:图片、攻击力、武器。
这些是零散的东西,总得有个角色把它们组合起来吧?所以,这个角色就是实体。
而组件是千奇百怪的,比如:坐标。
在产生点击事件的时候,得有个实体把坐标给组合起来,那么,就有个“点击事件实体”的东西了。

 

至于System(系统),可以理解为Controller(控制器),用来控制实体逻辑的。
不理解没关系,看完这篇的HelloWorld大家就明白了。

 

2. 创建Component(组件)

好吧,我们开始。
Entitas的基本思想就是,把实体和它的属性完全分开,以组件的形式组合这些属性。

 

我们从创建组件开始一步步走向HelloWorld吧。
创建一个DebugMessageComponent.cs文件,代码目录结构就随意了,只是学习而已。

 

注意两个地方,一个是给类加上一个[Game]特性,从目前我所理解的情况来看,这个Game的特性代表了这个组件是属于一个叫做GameEntity的实体。
这个组件叫做调试信息,拥有这个组件的实体就代码它拥有了调试信息这个属性。

3.自动生成Entity(实体)

Entitas会自动帮我们根据组件生成实体,我们是不需要在实体的创建上花费太多心思的。

 

现在,回到IDE,依次选择【Tools】-【Entitas】-【Generate】:

你会看到项目下多了一个GameDebugMessageComponent文件(Generated目录下都是自动生成的文件,不要去修改它们):

 

文件内容如下:

 

该文件里包含两个类:GameEntity和GameMather。

 

如之前所说,我们给组件赋予了[Game] 特性,所以它会帮我们生成GameEntity实体(的一部分)。
如果你仔细看的话,会发现,GameEntity是用partial定义的,也就是说,它是一个分部类。

 

什么是分部类?就是把一个类拆分为多个部分,在不同的地方定义。
并没有什么特别的,只是方便我们做不同的处理,比如在不同的文件里定义同一个类,这个文件定义一些属性,那个文件定义一些函数等待。

 

而Entitas会根据不同的组件生成多个实体的分部类,每个分部类里只定义一个组件的相关操作,这是Entitas的特点之一。
至于GameMatcher,是用来筛选实体的,这里暂时不多说。

 

4. 创建“控制器”——System(系统)

对于Entitas,组件只是定义一些属性,实体是自动生成的,而我们要做的事情大部分都在System里。
现在,我们来创建一个新的C#文件,命名为:DebugMessageSystem.cs

 

其内容如下:
这个System比较关键,我分步解释一下:
  • a 通常情况下,我们的System类都要继承ReactiveSystem(还有其他System我们以后再说)
  • b ReactiveSystem是干什么的呢?可以粗暴地理解为:监测那些属性发生了改变的实体,然后对它们做一些厉害的事情
  • c GetTrigger函数的作用:一个System通常只对某些类型的实体感兴趣,比如我们的DebugMessageSystem,它只对那些拥有DebugMessage组件的实体感兴趣,GetTrigger函数就是用来筛选实体的。之前生成的实体里包含了一个GameMatcher类,它也是一个分部类,作用就是筛选实体类型。
  • d Filter函数:这也是一个筛选函数,为毛已经有了GetTrigger的情况下还需要Filter函数?因为,GetTrigger函数仅仅是筛选实体类型,但是并不是这个实体类型下的所有实体我都感兴趣,Filter函数就是在已经筛选了实体类型的情况下,再根据具体的需求进一步筛选。这里筛选的就是那些有打印信息的实体。
  • e Execute函数是重点,经过GetTrigger和Filter的重重筛选后,我们终于得到了自己感兴趣的实体。这些实体会通过Execute的参数传递进来,我们可以对这些实体做我们想做的事情(咳咳,注意道德底线)。比如这里我们就是把所有有打印信息的实体的信息打印出来。

5.Systems(系统组)

所以,我们可以开始HelloWorld了么?
不,还不行,我还想继续说(旁白:那你自己说个够吧,反正我已经听不下去了)

 

快了快了,大家坚持一下。
我们现在要来创建一个管理System的System,因为一个游戏开发过程中,不可能只有一个System的,为了方便管理,便有了【Feature】System的概念。

 

我们先来创建一个TutorialSystems.cs类,内容如下:

 

这个类要继承Feature,它的内容很简单,就是在构造器里Add所有System进去,我们现在只有一个DebugMessageSystem,所以只需添加一个。
Feature就像一个管理System的管理器,有什么好处?等会大家就知道了。

6. 最后一步——让Entitas的东西和Unity关联

之前我们一直在做的事情基本上都和Unity无关,因此,想要让这组件、实体、系统运行起来,就必须把它们关联起来。

 

我们来创建一个GameController.cs文件,内容如下:

7. 运行?

所以,我们可以运行了?
差不多是吧,在Unity里创建一个GameObject,然后把GameController挂上去,然后就能运行了。

 

所以,大家看到HelloWorld了吗?(旁白:并没有!)
看不到就对了,这就是Entitas的神奇之处。(旁白:神奇你妹啊!我只是想看个HelloWorld,再不出现我就Alt+F4了啊!)

 

大家别急(靠,我自己都急了),虽然所有代码都正常运行了,但是别忘了,我们的DebugMessageSystem的Execute函数是什么情况下执行的?
拥有DebugMessage组件的实体(GetTrigger函数限制的),并且hasDebugMessage属性为true(Filter函数限制的)才会触发Execute函数。

 

我们现在没有任何GameEntity,是不可能触发Execute函数的。
什么情况下才有新的GameEntity出现,这个是由我们来决定的,这个问题就和“什么时候出现怪物”是一样的。

 

不过,既然是HelloWorld,我们可以自己添加一些测试实体。
方法就是,在GameController的Start函数里自己添加实体,代码如下:
获取game的上下文对象,调用CreateEntity函数即可创建实体。
创建完实体后呢,对,得给它添加DebugMessage组件(AddDebugMessage函数),添加组件的同时传递一个DebugMessage字符串。

 

于是,这个实体就同时满足了【拥有DebugMessage组件】、【hasDebugMessage属性为true】的条件。
再次运行游戏,在Console里,大家会看到姗姗来迟的HelloWorld…太感人了。

8. 唠叨一下

可能大家觉得,Entitas的HelloWorld也太难出现了吧,得写一堆东西。
确实,毕竟是框架,不是语言。
我们得按照框架的把代码搭起来才能做一些简单的事情,可能大家对于Entitas的认识还是很模糊,我已经把官方的HelloWorld教程精简了,可它还是很复杂。

 

下一篇我就和大家讲解Entitas的基本思想,帮助大家了解这个框架。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注