开发笔记(1)
折腾了好久,终于可以开始正式项目开发了。
之前的这段日子,我们陷落在公司的股权分配问题中,纠结于到底需要几个人到位才启动;更是反复讨论,到底应该做个怎样的游戏。林林总总,终于,在已经到位的几位同学的摩拳擦掌中,叮当决定自己挂帅开始干了。
就这么不到十个人,空旷的办公室,跟我们起先想像的情况不太一样。尤其是主策划还没有落定。我说,叮当,你好歹也是一资深游戏玩家,带了这么多年的游戏部,跟了这么多成功的项目,没吃过猪肉总见过猪跑吧,我就不相信你干着会比别人差。若不是我必须盯着程序实现这块,我都想自己做主策划了。不过有你干,我放心。
主策划的位置,咱们可以先空着,前期工作不能延。产品经理代理一下游戏主策划的位置也是创业公司必须的;正如我这挂牌的 CTO ,除了负责系统架构以外,也得兼个程序员做实现嘛。
经过两天对项目计划表的讨论后,我们今天就算正式开工了。
游戏是怎样的?半保密,不在这里多写,怕大家骂。再说了,这个东西现在说是怎样的,一两年后肯定有变化,多说无益,多解释无益。简单说呢,就是一个战斗系统类似魔兽世界,但系统核心玩法差异很大,更为轻松,更偏重 PvP 的 MMORPG 。为什么是这样一个东西,不想解释,反正不是拍脑袋想出来的。
既然是开发笔记,就写写现在在做些啥,打算怎样做下去。
我们先集体玩了一周魔兽世界,虽然大部分人已经是 wow 老玩家,但还是有一两个人玩的比较少,大家一起熟悉一下。主要是熟悉战斗系统,还有美术风格的感觉。培养点兴趣,对未来我们自己做的东西至少在表层上大家都有点感觉,有爱。
瞥开美术和策划的计划不谈,主要写写程序的计划。
在 Closed Beta 前,有 8 个历程碑,到一期截至,就开始有内部运行的版本。这次完全抛弃以往在网易积累的任何一点成品,全部从零开始做。但是,对于程序员来说,一切都在脑子里,其实工作量并不大。有机会重头来,恐怕是大部分程序员梦寐以求的机会。
当然,我们购买了一套 3d engine (不介绍,不解释),起点高一些。服务器也会尽量用一些成熟的开源库。
一期打算实现基本的用户登陆,场景漫游,包括在场景中做各种跑、跳、走、骑乘等动作。
一期程序员三人:
云风:负责总体规划,总体协议设计,以及部分服务器模块的实现。
怪物公司:负责客户端的设计与实现。
蜗牛:负责服务器的细节设计与实现。
吵架是我们的传统,自今天就开始了。按照惯例,我无法说服项目组认可我的所有设计和技术选择。不过大家妥协的结果是,先按我的想法做,一期雏形在下周末前完成,根据实现过程中遇到的问题,我们在修正甚至全部重构目前的设计。一周半时间的代价是目前我们可以承受的。
ps. 程序员就是这么一种奇怪的生物。好的程序员都有自己独立的思想。对自己实现或即将实现的代码有爱。按照别人的思想去实现是件无比痛苦的事情,会觉得在浪费自己的生命。所以,大部分有活力的项目开始都是一个人建立起来的。在大公司,好多老程序员都喜欢招聘所谓有潜力的新人,认为他们白纸一张,好塑造。说到底就是听话。但事实的结果一般是,要么培养出来一个庸才,无法担当;要么,在技术选择上最终分道扬镳。我总是对他们说,想想你愿不愿意总听着别人的意见干活?如果你不愿意,那么就别指挥别人干。自己不愿意做的事情,就别让别人帮你做。
我的设计草稿是这样的:
整个游戏系统(一期工程需要的)大体由这样一些部分组成:
客户端,运行在玩家的终端上,用一条 TCP 连接和系统通讯。它接入游戏服务器网关。
网关,负责汇总所有客户端,大体上和我很多年前的想法一致 ,虽然会有一些实现上的小改变,但思想没有根本变化。
客户代理(Agent) ,运行在网关的后端,在逻辑上,每个客户端都有一个 agent 负责翻译和转发客户端发来的请求,以及回应。众多 agent 可以实现在同一个进程中,也可以是多个不同的进程里。可以用脚本虚拟机的形式跑,也可以是别的形式,这些都不太重要。这一次,我们最大可能使用独立的 lua state 来实现单个 agent。
数据服务,保存玩家数据,场景数据等。前端用自己的代码和协议同系统其它部分沟通,后端这次想采用 redis 做储存。
场景管理器,用于管理静态场景和动态副本。
若干场景服务器,用于玩家在里面做漫游。
网关之后的服务是相互信任的,并组成一个虚拟网络可以相互通讯。通讯底层暂时采用 zeromq ,通讯协议采用 google protobuf 。
客户端到 agent 的通讯协议与网关后各个逻辑结点之间的通讯协议将隔离,分开设计。甚至不保证采用一致的技术实现方案,以及协议设计风格。
这里的设计关键在于 Agent 的设计,大部分的工作量是围绕它而来的。
单个 Agent 的工作流程代表了项目一期的结果会展现的东西,大体上逻辑流程如下:
等待用户认证
把认证系统交给认证服务器认证,失败则返回 1 重试。
从数据库获取用户数据(一期数据很少,仅有默认的用户名,用户形象) ,并转发给客户端。
取得用户所在场景号,从场景管理器取得场景服务的位置,并申请加入场景。
从场景服务器,同步环境。
转发用户在场景中漫游的请求,并同步场景的实时数据。
一旦客户端发生异常或得到推出消息,通知场景服务器离开。
这里,和历史上我们的游戏服务器设计有一个小的不同。我认为,用户的角色在场景中的位置,动作状态,甚至以后的战斗数值状态,都是属于场景数据的一部分,而不是用户数据的一部分。
用户数据中,和场景有关的只包括他当前所属的场景。由场景自己来保存角色在场景中的状态数据。简单而具体的说,类似网易历史上的西游系列,玩家的坐标是玩家的属性之一,是会在持久化时存放在玩家数据里的。经过我这两年的思考,我觉得这种设计方法是有问题的。
从我现在的直觉上来说,虚拟角色的属性不应包括角色的地理位置信息。那是角色的外在约束。而场景更应该拥有在它其中的 PC 和 NPC 的位置以及各种状态。PC 下线只应该认为是 PC 处于一种特殊状态(不被周围的 PC/NPC 所见或影响),而并没有脱离这个场景。所以我更愿意把 PC 下线定义成 detach ,而上线则是 attach 的操作。在这点上,场景,作为一个实体,拥有它自己的数据逻辑。
agent 相关的协议粗略的设计如下:
- auth 登陆认证
- user/pass 取得 userid ,返回成功或各种失败
- userdb
- 用 userid 取得 avatar list
- 用 avatar 取得 avatar data (包括场景名)
- scene manager
- 用 场景名 取得 scene id
- 用 scene id 取得场景状态,返回允许进入或各种拥堵状态
- scene
- 把 avatar attach 到场景
- 取得 avatar 的场景上下文
- 把 avatar detach 出场景
- avatar 设置坐标,速度,行为(跑,走,站立),方向
- avatar 骑乘状态改变
- avatar 做特定动作
好吧,未来一周的工作任务就是这些了。需要明天再做细化整理。然后就是实现了。