本文章针对的网络库antnet

ECS这两年非常火,特别是在游戏设计中,那ECS对游戏有没有革命性的帮助呢,从我最近的工作来看,ECS确实有革命性的效果,不过对手游来讲可以没有体现的那么明显,因为即使用传统的OOP来写,性能也基本足够。但对我来说,ECS可以说是开发必需,因为现在我主要从事H5相关工作。

可能有人会说,不就H5小游戏嘛,要用什么高大上的技术吗。

确实,如果只是做一些沙雕小游戏确实不需要,但我要做到是手游,能在微信里面跑的手游。2020年手游的品质有多高大家都清楚,这样品质的游戏要能在微信里面流畅运行时非常困难的,特别是ios,由于没有jit,更是难上加难。

我们做的H5游戏不仅渲染按照手游标准,而且同步也要求手游标准,甚至更高。微信有个弊端,就是如果游戏跑在微信上ping会增加30~50ms,可能和微信底层的处理相关。但对同步来说,要求就更高了,现在零延迟手游基本已是主流。如果在微信上面达到真正的零延迟手感,需要更多的努力。

因为我们的标准很高,同步基本上只能以ECS来实现,否则很难实现零延迟的手感,至于为什么ECS能够达到零延迟的手感,等后续文章详述。

ECS里面最有几个难点:

一个是E,因为E相对简单,在我们的系统里面E就是一个int32,确实简单,但管理E和C关系的系统,就复杂了。可以说这个管理器,就是ECS系统的核心。

另外一个是S,很多ECS系统往往就卡在S了,很多游戏写着写着越来越像EC模式,而不是ECS,就是因为S不好设计。

刚刚提到E和C会有一个管理器,在我们的设计里面就是EntityWorld,而为了实现这个管理器,需要大量的map作为基本数据结构,在我们性能压测中,因为要经常获取组件和添加组件,在上万个实体的系统中,golang的map表现非常糟糕,已经成为性能的卡点了。

为此,我再antnet中加入了array_map这一结构,成功解决了map作为基本数据结构的西能问题。

作为Map来讲,核心问题还是增删改查,但作为EntityWorld,还有一个问题需要考虑,就是唯一性,因为数组的大小往往不会设计得太大,那么数组的空间可能会重用,比如删除了一个E,立马又被重用了,但C里面可能记录了EnityID,就可能出问题,所以我在array_map设计了代的概念,每次删除代都增加,保证不会出现复用的情况。