基于ECS的大地图同步方案(上)

最近打算回顾一下在自己在slg向的沙盘大地图游戏开发中遇到的一些问题和解决方案,本篇(大概会分上中下3节)主要讲述大地图同步的相关问题

游戏玩法概述
  • 支持数千人在同一张大地图上建造、采集、争夺地图资源的网络游戏
  • 玩家可以自由的浏览整个沙盘地图
  • 玩家可以自由的控制多只部队在沙盘上移动、战斗
游戏数据的抽象分类
  • 静态的沙盘地图
    • 地形地貌
    • 固定的战略要地(如关卡、要塞)
  • 沙盘上的动态对象
    • 玩家的建筑、部队
    • 周期刷新的资源点
    • 地图的占领状态
  • 玩家的养成数据
  • 玩家之间的关系
游戏数据同步方式
  • 静态数据无需同步,由服务器客户端各自按需从配置表或资源文件中读取
  • 沙盘动态实体通过ECS框架进行同步
  • 其他数据如养成数据、关系数据,由相关的游戏子系统通过传统的C/S消息同步
沙盘同步思路

如果强行要对沙盘同步方案分个类的话,应该属于状态同步(另一大类是帧/锁同步)。
对于大地图游戏来说,游戏世界内存在着大量的游戏对象,全部同步对服务器和客户端都是无法接受的。
所以首先我们要确定一种规则筛选出有限的对象同步给玩家。受游戏玩法的影响,不同于传统的MMORPG类游戏,slg向的游戏一般是上帝视角,可以不受约束的将视窗移动到地图的任何位置,所以MMORPG的以控制角色为中心的视野对+9宫格的同步方案就不适用了。我们采用地图块+视野窗口的模式来决定需要同步的对象。


九宫格.png

!
视野窗口.png

接下来我们要设计一种结构来组织游戏世界中的各种对象,让它们的创建、交互、变化更新、销毁等等行为变得可控、易于同步。
传统游戏设计中大多采用面向对象的方式来设计,将游戏中的每一种事物(玩家、npc、资源点、帮会等等)封装成一类对象,每个对象有一个update方法,在主循环中不断遍历这些对象,调用它们的update方法实现游戏逻辑。
这是一套非常经典的模型,非常符合人的思维方式,并且也在各类游戏中得到了广泛的应用。不过它在某些方面有不是完美的。比如:

  • 随着游戏功能的不断扩展,可能导致一个类中的内容会不断膨胀,或者会产生复杂的继承关系,再或者类多到爆炸,并且类之间的界限难以区分。

  • 游戏系统以类对象为单位进行遍历,但往往这些对象中并不是所有的对象都符合系统本次遍历的需要,这时候实际上会产生很多的无效update

归根结底是因为OOP是以对象为核心,将所有的数据、方法全部集成到一个类对象的内部,由这个对象拥有全部的数据,并且负责处理全部的事务。

ECS框架

假设我们以功能逻辑为核心,将原来集成到一个对象内部的数据按功能进行切片,拆分成若干独立的功能组件(这里的组件可以理解为数据的载体,它提供基础的读写方法,但自己不包含引起变化的逻辑)。
系统负责驱动逻辑,在一次update中,会取出这个功能逻辑所关心的组件列表(功能操作涉及到的数据),遍历组件列表执行对应的功能函数。
举一个具体的例子:假设游戏中有一个对象叫做兵营,它存在于地图上,可以进行建造升级、移动、生产士兵,也可以被攻击摧毁
如果是传统OOP的写法,可能会写这样一个类

class CBarrack
{
  //建造进度相关数据和函数
  //移动相关数据和函数
  //生产进度相关数据和函数
  //耐久、燃烧状态等数据个函数
};

然后会用一个容器存放所有的兵营,比如List<CBarrack>
在主循环中,我们会遍历这个list,取出每一个兵营对象,并依次调用它的建造、移动、生产、耐久相关的方法,完成状态的更新。

现在我们把兵营的数据拆分开来,由这4个组件组合而成:

  • 建造队列组件BuildComponent
  • 移动组件MoveComponent
  • 生产队列组件ProductComponent
  • 战斗属性组件BattleAttrComponent

每一种组件有一个对应的容器统一管理,比如主城、矿场、医院的建造队列组件都放在同一个容器中


ECS.png

在建造系统中,我们遍历所有的建造队列,处理建造相关的逻辑(此时不光是兵营的建造组件,所有含有建造组件的实体的建造组件都会被一起处理)
在移动组件中,处理所有的移动逻辑(同样,这里的移动组件的所有者可能是部队、野怪、建筑)
更进一步,当建造完成时,可以将建造组件从兵营实体上移除,那么在下一此建造系统的遍历中,就不再需要遍历兵营了。
而假设后续游戏功能里又加入了一个部队可以驻扎到兵营中的功能,我们可以单独写一个驻扎组件,然后挂接到兵营实体上,而不需关心也不会影响到兵营已有的逻辑。
再假设这个驻扎的功能又改成兵营不能驻扎,而是箭塔可以驻扎,那么只需要把驻扎组件从兵营上移到箭塔上即可,外部系统完全无感。
这种以功能逻辑为核心,对对象的数据进行切片和组合的设计框架,被称作ECS(Entity+Component+System)框架

  • Component(组件):对象中可以被独立处理的若干数据(或者说属性)的载体,提供对数据的最基础的读写功能,但不包含其他逻辑
  • Entity(实体):对应OOP中的对象,只不过再ECS框架中,Entity只是一个“壳子”,一个可以按需求动态添加和移除组件的容器
  • System(系统):游戏逻辑的驱动者,它提供实现各种功能的函数,关心的是实现功能所需要和会影响到的数据(组件),而不关心这些组件具体是属于哪个实体

ECS与状态同步的契合之处在于,状态同步关心的是游戏对象的数据(状态值)而非操作指令,而ECS本身就是由数据驱动的框架,服务器可以最大程度上只告诉客户端游戏对象的当前的数据是什么,而不是游戏内发生了什么。
至于ECS如何与具体的同步实现相结合,请听下回分解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容