关于ECS设计以及MVC分层设计和组件化设计的思考和总结(这个标题就问你长不长)

前言

最近工作忙了很多关于设计的事情,用了常用的分层设计MVC也尝试是用了ECS这种设计方式,同时也参考了Unity或者Creator的这种组件化方式。有了很多困惑也有了一些总结。

首先,MVC也好ECS也好他们都是一种编程的范式,或者说你组织代码的方式。然而他们的层面不同,也就是说不是一个层面的东西。

  • MVC:用来解决UI交互方面的成熟的经验体系,是一种分层的设计。
  • ECS:是一种对象组织的方式,比如继承也是一种处理对象关系的方式。而ECS就是组合的方式来处理对象见关系的,还看到了一种说法:

Entity system architecture derives from an attempt to resolve the
problems with the game loop. It addresses the game loop as the core of
the game, and pre-supposes that simplifying the game loop is more
important than anything else in modern game architecture. More
important than separation of the view from the controller

也就是说ECS这种方式目标是用来尝试处理游戏循环问题的。并预先假设简化游戏循环比现代游戏架构中的任何其他东西更重要。比从控制器分离视图更重要。


同样,还有很多的架构,比如分层设计的系统架构等等。
简单的总结来说,他们不是一个层面的,MVC是一种分层的针对UI交互的设计,而ECS是一种处理对象关系的方式。

为什么我上面会困惑,就是我把不同层面的东西放到一个平面上来思考讨论了。就像你有一个衣服柜子,用它来放鞋子okay么?是的可以放,但是会不会别扭?会的。这就是我的一些困惑,可能这个例子并不恰当,但是用来说明不是一个层面的东西应该足够了。

关于数据驱动与解耦的方面

ECS其实更是解耦的终极方案,处理更复杂问题的一种更好的方案。另一方面MVC并不是不关注数据驱动,想要使用好MVC数据的驱动也是必须的才能更好的解耦。只不过MVC更关于也更适用于UI方面的交互罢了,当然这也是一种经验模型,后来的MVP以及MVVM都是一种优化或者特别场合的提升。

总结

MVC以及ECS不是一个层面的东西所以理论上不会有冲突。
至于适用场合,个人感觉:如果涉及ui交互比如某一个界面显示某些东西,同时这个ui可以出发一些事件这种还是MVC更方便一点,因为你用ECS会发现你无从下手,比如你是单独写个view的组件?这个view触发的事件呢?以及这个view所依赖的数据呢?都写到了一起?你会发现写着写着都写到了一起结构很乱。可能目前我并没有找到什么合理的方式。关于ECS的使用,其实目前如果基于creator来开发,并不是纯粹的ECS思想而是类似unity老版本的一种C-S的结合体的组件。什么时候以及什么场合使用,个人感觉是GamePlay的场景,

引用wiki的一句话:Gameplay is the pattern defined through the game rules.
也就是游戏玩法。

因为游戏的玩法复杂度很高,变化很多,这种时候利用组件的方式去实现游戏玩法,能保证各种玩法的组合,这样使用更加方便贴切。


PS:补充

临时有了想法作个补充,我说ECS是一种处理对象之间关系的方式。那MVC呢?这个不是么?我们都是面相对象编程,View是个对象么?Controller是个对象么?这个不是处理对象见关系的么?其实我想回答,是的。我们几乎都在处理各个对象。为了实现某个业务,把各个对象组织起来。好的代码就是轻度耦合实现。
但是,我想说,还是重点不同,其实MVC,我们本可以用一个view代码来实现所有,在view的代码里做很多处理控制。我们也能实现一个对象完成业务,可是为了应对频繁变化的需求慢慢演变出了MVC,它是一个解决方案。这就是侧重点以及面向的层面不同。
而ECS处理起真真切切的各个对象的时候,就会很自然而然。组合各个对象成某一个或者某一类对象,或者更合理的应该是,组织各种各样的数据?比如position组件,组织x,y坐标数据。这种面向数据的东西,或者说更注重这个数据的东西用ECS这种组件的方式更贴合。这个可能就设计到了为什么用组合而不用继承的这一系列讨论。比如这篇文章:What is an Entity Component System7


贴一下一些朋友对于ECS和MVC方面的见解

把ECS按在下层,使用轻MVC模式。首先考虑的问题是如何分层的问题,如果一个属性能够提炼成通过的ECS模型(比如你说的player相关属性),那么我会把这个属性沉淀,做成一个通用的C-S系统。这个系统和其它的系统以后都是以子系统的模式出现,在它的上面才是MVC,这里处理具体的UI交互问题。具体来说我们的应用分为基本的两层,上层用MVC来处理交互,下层用ECS或者其系统来处理各种各样的问题。关于轻MVC模式之所以这么说是因为游戏上的生命周期短,我很少真的去设计完善的MVC模型,基本上是意思到了,达到我心中的代码整洁、解耦清晰同时改起来又方便的时候就可以了。


过了好久了,偶然看到unity的 tiny project 一个为2d游戏提供的package,其实这个并没什么,但是重要的是它完全使用了ECS的这种模式,然后又给了我一些理解和启发这里补充下。

看过相面的一些想法和记录就明白其实我原来写的ECS的并不是ECS感觉上更像是组件化而已。

我们先来看看为什么有这个tiny project
在这里插入图片描述
很明显,对当前untiy的monobehavior和ECS做了一下对比。
引用类型值类型
数据散到内存的各个地方内存紧紧排列
在操作期间处理不需要的数据(其实我们需要model的一个数据反而传入了整个model)我们只处理需要的数据
高下立判,从第二点和第三点上我们就可以看出ECS的提升了对于性能上,内存紧凑跟容易让cpu进行寻址预判,处理只需要的数据更容易解耦复用。

然后再专业的看一下 ECS的各个结构的意义
在这里插入图片描述

Data Data Data 重要的事情说三遍
其实也很好理解,我们从class引用类型换成struct值类型,就像我们写c程序一样,所有的一切都是内存都是数据。

  • component就是单纯的数据而已,什么speed | health | name …等等
  • entity 就是一个单纯的一组component而已 并不是什么Object啊 什么你以为的Node啊之类,就是单纯的一组component而已,这里另一个设计概念就是我们的entity不允许同类型的component所以这里用了set
  • system就是操作数据而已,就是单纯的操作数据

这里让我受到启发和解惑的一个例子我觉得一定要举出来看一下
在这里插入图片描述
这是两个component的例子,一个heath一个sprite2D 很简单,都是struct,都是我们要用的数据,数据,数据再次强调。其实很长时间困扰我的一个问题是:
我经常会吧entity当做容器,弄什么都把component集合到这个entity上来,然后在表现一些东西上就会卡住,而这里给我们演示了,Sprite2D的其中一个数据就是Entity 是个image。这个乍看上去怎么怪怪的,就像我的思维,我们只吧entity当做容器,只有entity里才能放component,就是这样才限制了我们。所以这了再次强调,不要把entity当做容器,很容易让你困惑,就当做一组数据而已就好,就当做一组数据而已就好,就当做一组数据而已就好。那么我们一组数据里放另一组数据行吗?答案当然是和okay啊!就像我们写c程序struct里嵌入一个struct有啥问题么?组合一个有啥问题么?当然没有了。 当然了,这里image这个entitiy里有啥就得去看它这个struct里都组合了哪些数据了。所以 一切皆Data,一定要理解这一点。

阅读更多

没有更多推荐了,返回首页