美文网首页
Entitas —— 示例 "Match-One" 拆解

Entitas —— 示例 "Match-One" 拆解

作者: 珏_Gray | 来源:发表于2019-06-04 11:43 被阅读0次

原工程链接:
https://github.com/sschmid/Match-One

Match One

This is a simple and interactive Unity3d example project to show how to use Entitas. Entitas is a super fast Entity Component System (ECS) Framework specifically made for C# and Unity

Get Entitas here: https://github.com/sschmid/Entitas-CSharp


Match One is a very simple CandyCrush-like Match 3 example, except it's Match One.

Watch the talk from Unite Europe 2015 to get an in-depth tutorial.

Match One shows

  • systems list in GameController
  • how you can use reactive system to only process changed entities
  • the usage of EntityIndex for super fast entity access
  • how you can use multiple pools to reduce the memory footprint of each entity (Input, Core, Score)

Match One

虽然Unity官方推出了ECS,但仍处于非常早期的阶段,因此推荐先使用较为成熟的Entitas来提升自己对ECS的理解。虽然二者对于ECS的实现方式不同,但整体上的结构是类似的,不熟悉的ECS的小伙伴,请先搜索相关的知识。

强烈推荐先阅读:
如何使用Entitas开发游戏(FNGGames)

功能 Features


工程的Features文件下包含了所有关于该游戏的代码(Generated文件内是自动生成的代码)。这些代码定义了Component,System还有Service(如Unity的渲染、随机发生器、引擎输入等)。

面向数据编程跟数据库技术有想通的地方,可惜我并没有系统学习过数据库方面的知识,但这里还是借用表的形式来展开。

ALL COMPONENTS:

Components Values About
PositionComponent Vector2Int pos 2D位置
PieceComponent 用以标识“棋子”的标签
MovableComponent 用以标识“可移动物体”的标签
SelectedComponent 用以标识“被选中”的标签
InteractiveComponent 用以标识“可交互”的标签
DestroyedComponent 用以标识“被销毁”的标签
BurstModeComponent 用以标识“Burst Mode”的标签
BoardComponent Vector2Int size 2D棋盘大小
GameConfigComponent Two getter function for boardSize & blockerProbability 这个组件比较特殊,其实是个interface,定义了两个方法
InputComponent Vector2Int mousePos 鼠标输入坐标
ScoreComponent Int score 分数
AssetComponet string path 资源路径
ViewComponent IView view 包含一个Link方法Interface,将entity和Unity的gameObject关联

ECS中,System是没有状态的,只负责行为,因此游戏中所有状态都由Component负责。在过往的编程中,我们常使用bool变量来表征物体是否处于某个状态,在ECS中我们使用tag component(空Component)。

All ENTITIES:
需要提醒的是: 与面向对象编程每种物体定义一个类再实例化不同,ECS是创建一个Entity(可能是类,也可能是ID,依赖于不同的实现方式),之后将Components与之关联,根据不同Component的组合来实现差异化。

Entities Owning Components About
Game Config Entity GameConfigComponent 记录游戏开始前在game config资源中配置的数据,即棋盘大小,和blocker出现概率
Score Entity ScoreComponent 记录得分
Score Listenner Entity AnyScoreListenerComponent 这个component在上面列表中没提到,这个component有点类似语法糖,它记录了一系列方法,当ScoreComponet发生改变时,会自动调用这些方法。当然我们其实也可以写一个System来实现这个功能。
Input Entity InputComponent 当鼠标点击时动态创建,记录鼠标点击位置,经过System处理后自动销毁
Burst Mode Entity AnyBurstModeListener & AnyBurstModeRemoveListener 监听burst mode component的变化
Gameboard Entity BoardComponent 棋盘,记录大小
Piece Entity Asset, Destroyed Listener,Interactive,Movable,Piece,Position,Position Listener,View Component 棋子,最复杂的Entity

我们看到除了上面的列表中所列的Component之外,多了不少自动生成的xxxListener Component,这些组件保存了方法的入口,需要提醒的是,这在Unity ECS中是禁止的。我们可以写system来实现类似的功能。
还有一个与面向对象编程不同的是,创建和销毁entity的开销是非常小的,因此我们可以“疯狂”地动态创建和销毁entity(销毁关联的component可能要一些开销,但比起面向对象中对象的操作要高效得多),将其作为刺激System运作的pulse脉冲输入。

ALL SYSTEMS:

Systems Related Components Behavior
Board System Piece , Position ,Board , GameConfig 创建棋子,并将其放在正确的位置上,响应棋盘大小的变化
Fall System Destroyed , Piece,Position 当有棋子被标记为销毁,移动剩余棋子
Fill System Destroyed , Piece ,Board ,Position 当有棋子被标记为销毁,添加新的棋子
GameCleanupSystem Destroyed 销毁所有标记为销毁的entity
InputSystem 执行Unity的输入检测,并动态创建entity
ProcessInputSystem Input 根据input component中的值找到对应位置的entity,为其添加destroyed component
InputCleanupSystem Input 销毁所有带有input componet的entity

其实还有一部分是关于View部分的system,大家还是下载工程来看吧,很容易理解的。

系统执行顺序
关于系统顺序,有的时候并不需要严格按照思路中的逻辑排序的。比如这里,是先标记destroy tag,在帧的末尾才真正执行销毁。更有甚者,许多逻辑是不必要在一帧内执行的,可以容忍1帧的延迟,比如物体的生成和表现。之所以提这个,主要是考虑到Unity ECS中的Job System多线程并发。我们没必要添加多余的依赖关系。

Primary Index


工程中使用PositionComponent的值来检索在该位置上的entity。

添加PrimaryIndex
其中的
(e,c) => (c as PositionComponent)?.value??e.position.value
我并不太清楚为什么要这样写,目的是为了得到vector2Int类型值作为Key。
我们还要注意这里的group中排除了DestroyComponent,所以即使我们不删除entity,只要添加了DestroyComponent,用vector2int值为key,调用

也会返回null。因此,就算不删除entity,Fall、Fill System都能正常运作。在Unity编辑器中,会看到许多具有相同position的entity,但有且只有一个没有DestroyComponent。

这里就引出了一个问题,如何通过component的值查找对应的entity?
最简单的方式当然是遍历具有该component的entity,逐一比对。Entitas中可以利用键值对。Unity ECS,还没研究。

相关文章

网友评论

      本文标题:Entitas —— 示例 "Match-One" 拆解

      本文链接:https://www.haomeiwen.com/subject/fhwvtctx.html