游戏要素

1. 二进制数据传输

游戏对于性能有极高要求,所以通过二进制数据传输来提高游戏的性能,一般使用 protobuffer,这是游戏的基本要素之一。

2. WebSocket 协议

HTTP 协议因为包头的问题,导致无效内容过多,而 WebSocket 协议可以尽可能减少这些无效内容,并且默认使用二进制,这是游戏的基本要素之二。

3. 加密机制

后端发送到前端一般无需加密,但是前端发到后端需要加密,这里巧妙的利用了二进制的好处,也就是 buffer,通过异或的方式进行简单加密,这是游戏要素之三。

4. 日志系统

游戏日志内容众多,因为涉及到复杂逻辑,所以在架构上需要对日志做出特殊要求,比如报错日志需要发送到指定的地方,比如微信,或者一些辅助平台,这是游戏的基本要素之四。

5. 数据存储

游戏服务和传统 Web 应用有一个显著差异:状态管理。Web 应用通常要求无状态,多个服务实例可以同时运行,每个请求的上下文(Context)生命周期从用户鉴权开始到请求完成就结束。

而游戏服务由于其特殊性(单服务器承载固定数量的玩家,玩家间存在复杂的状态交互),需要维护状态。这就要求采用合适的数据存储策略:将热点数据存放在内存中,定期持久化到数据库。在正常游戏运行时,大部分数据操作直接在内存中进行,这是游戏服务的第五个基本要素。

游戏架构

1. 骨架模块

首先确立骨架模块,这个模块负责管理其他模块,项目入口也在这里,比如:

  • 初始化日志
  • 初始化游戏逻辑模块

这里可以抽象出一个 module 的类,这个类主要有几个基本的内容:

  • init 方法:做项目初始化
  • start 方法:逻辑启动
  • run 方法
  • destroy 方法

之后扩展的所有模块都需要实现这些方法,这样的目的是为了方便管理。

2. WebSocket 模块实现

这个模块主要内容是:

  • 接收客户端连接
  • 监听消息
  • 发送消息
  • 关闭连接

当客户端和服务端建立一个 ws,需要通过 WebSocket 主模块保存这个连接,方便后续管理,比如优雅的主动断开所有的 ws 连接。然后就是监听消息,并将消息通过骨架发送出去。

这里也是一个关键点,骨架模块作为基础,可以将其他模块挂在骨架模块上,然后通过骨架模块去调用其他模块接收消息的方法。

3. 模块间消息处理

前几步都是基础模块,这里一般就是逻辑模块了,比如游戏逻辑模块。这里接收到骨架模块传送过来的消息内容,就可以去查看是否有具体的方法来处理这些消息了。

另外,此时消息也已经被预处理过,比如:

  • proto 的解码
  • 前端加密消息的异或解密

架构到这里就基本结束了,后续就是具体的业务逻辑。

4. 数据存储

游戏中的数据存储需要建立专门的存储队列系统。由于玩家数据是一个复杂的集合体,存储时需要考虑各种异常情况,并且要能够追踪每条数据的存储状态。建议建立独立的数据库服务类,通过定时任务处理队列中的数据。

主要数据类型:

  1. 玩家信息

    • 基础属性
    • 背包物品
    • 任务进度
    • 社交关系等
  2. 地图信息
    地图数据是除玩家数据外另一个重要的数据类型,根据地图规模采用不同的存储策略:

    • 小型地图

      • 使用单一 UUID 标识
      • 存储内容:
        • 当前在地图内的玩家
        • 地图内物品的状态、数量、位置
        • 地图特殊事件等
    • 大型世界地图

      • 采用分块存储策略
      • 原因:
        • 避免触及数据库文档大小限制(如 MongoDB 16MB 限制)
        • 提高数据更新效率
      • 实现方式:
        • 将地图划分为多个区块(Block)
        • 每个区块分配唯一的 blockId
        • 独立存储每个区块的数据