Organizations

9 results for 游戏架构
  • 网络游戏的帧同步实现 本篇章主要实现多人在线的帧同步流程, 首先是定义客户端和服务端会用到的游戏交互事件 Protobuf: syntax = "proto3"; // 初始化最新的序列帧 - 这个事件是服务端和客户端双向共享, 也就是 Request-Response 响应方式 // 其实就是从服务端获取的最新序列帧ID, 然后挂载客户端目前已经执行的序列化帧上等待下个帧运行 // 后续需要初始化玩家坐标信息,场景信息也是通过该初始化事件加载; 比如下面声明初始化坐标位置[其实应该定义个 Vec2(x,y) 坐标结构] message InitFrame{ int32 frame = 1; // 后续初始化内容在以下扩充 float x = 2; float y = 3; } // 广播单项 - 玩家引发的发生帧变动 // 核心的 frame 字段是帧序列的编号, 需要确保客户端和服务端对发生帧做同步 // 当网络丢包重传的时候, 就能明确从那一个帧序列开始丢帧从而采用追帧方式让玩家回滚到最新状态 // frame 采用 uint32 最佳, 但无法确认开发语言是否支持 unsigned 特性, 所以采用到达最大值回滚为0重置或者设置int64也可以 // 从性能考虑来说采用 int32 就行, 对于小游戏来说 0 到 2^31-1 足够帧序列做行为序列处理 // 注意: 到达最大帧的时候服务端和客户端都要同步回滚处理才能对齐序列帧编号 message InputFrame{ string sessionId = 1; // 玩家唯一标识 int32 frame = 2; // 发生帧 int32 direction = 3; // 方向 bool jump = 4; // 是否触发跳跃 } // 广播事件 - 依据客户端提交的 InputFrame.
    游戏架构 Created Sun, 28 Sep 2025 20:39:05 +0800
  • 签到活动 常规来说手游内部的签到活动分为 7天签到(周签到) 和 30天签到(月签到) 的差异, 主要是增加玩家在线留存的手段. 这里采用 erlang 样例处理, 首先需要确定好结构: %%% @doc 7天签到记录(每周定时入库刷新), 保存进程内存 -record(sign_of_7, { ymd :: non_neg_integer(), % Ymd 格式的当天记录: 20241204 之类 state :: non_neg_integer() % 签到状态, 0 - 初始化| 1 - 可以签到 | 2 - 签到完成 }). %%% @doc 7天签到日志(签到完成保存), 保存数据库 -record(sign_of_7_log, { ymd :: non_neg_integer(), % 同上 item :: list() % 奖励 }). 这里就是设定 分钟级 别定时器确定上次签到更新时间, 比如 20241201 需要不断和当天 Ymd 做比较之后确认超过7天就刷新进度就行了. 同理30天签到也差不多是这种处理方式, 游戏内存只需要记录标识读取 Excel 道具发送给客户端消息即可, 日志库负责记录签到奖励数据入库.
    游戏架构 Created Wed, 04 Dec 2024 14:32:10 +0800
  • 游戏二进制序列化 近些年游戏序列化工具不断迭代更新, 比较知名的是 Protobuf|MessagePack 这种序列化, 如果性能要求不高甚至 JSON|XML 这种广泛集成语言也是可以作为游戏数据载体. 但是实际在项目使用当中发现其实 Protobuf 问题也很多, 包括以下问题: 项目引入不可预测的复杂性, 有时候版本可能出现冲突( ProtobufV2 和 ProtobufV3 ) 没办法适应性动态处理数据, 结构变动必须要对 proto 文件再编译导入游戏当中 而且对于小众语言来说, 可能根本没有具体实现处理 有的H5游戏上架平台对于底层数据读写功能要求很严格导致可能无法引入 特别是游戏项目, 很多都不采用外网软件库当中的项目引入而是自己内网重写相关功能, 所以对于游戏数据传输其实推荐更加采用原生二进制读写: 基本上是编程语言都支持, 真正跨平台处理, 不需要额外引入别的依赖 序列化过程可以自己动态处理, 不需要编译直接热更 这里采用 Java 语言做示例, 讲解怎么二进制在游戏当中怎么构建和传输. 数据结构 网络传输的数据结构一般常规以下几种: byte|int8: 8位, 1字节, 一般用来替代 bool 值做 0|1 状态等 short|int16:16位, 2字节 int|int32: 32位, 4字节 long|int64: 64位, 8字节 float: 32位单精度 double: 64位双精度 bytes: 二进制, 字符串做二进制处理, 首位 int32 后面就是结构数据 list: 列表数据, 首位 int32 后面就是结构数据 还有比较少用到的:
    游戏架构 Created Mon, 22 Jul 2024 21:18:40 +0800
  • 游戏服务架构(六) 前面已经构筑好了服务端功能, 但是目前只能知道请求确定已经到达, 但是并没有相关业务处理, 这里需要重新整合下目录: # 回到之前目录重新初始化 cd /data/game rm -rf /data/game/* # 创建目录 mkdir config # 系统配置 mkdir core # 核心基础目录 mkdir game # 游戏相关业务 mkdir proto # protobuf 的协议文件 mkdir tables # 策划 Excel配表功能 # 生成初始化文件 touch config/path.lua # 路径配置 touch config/net.lua # 网络配置 touch config/main.lua # 启动配置 touch run.lua # 启动入口 现在就按照正式项目搭建来介绍如何搭建正式商业化的游戏服务端 在开始部署服务之前最好认识下 skynet 所有对应的 api 确保清楚知道怎么回事. API 认识 skynet.launch: 启动一个C服务 skynet.kill: 强行杀死一个服务 skynet.abort: 退出Skynet进程 skynet.register: 给自身注册一个名字 skynet.
    游戏架构 Created Wed, 25 Oct 2023 15:25:45 +0800
  • 游戏服务架构(五) 上一个篇章编写简单的数值游戏, 已经集合了 游戏玩法-数据保存-协议传输 所有功能, 对于这种 自己玩自己 的游戏相对来说比较简单, 直接不推送消息做 JSON 数据同步即可. H5小程序的游戏基本集中于这种 但是可以如果想要扩展游戏本体, 可以看到目前功能缺少大量高级特性: 没有主动推送机制: 服务端无法发起推送消息功能 -> 需要考虑转化为 TCP/WebSocket 长链接 传递消息体过大: HTTP协议头+内容体导致消息庞大 -> 自定义传输解析 JSON无意义内容太多: 充斥大量 " 和 {} 符号冗余符号 -> 采用二进制流转化的序列化方案 短链接请求频繁: 短链接频繁来不及释放带来 504 请求错误 -> 走长连接访问 直接数据库IO拥堵: 可以看到访问数据操作是同步写入过高请求直接IO升高 -> 利用变成语言多核异步数据入库 注意: 如果没有经验最好采用 skynet 方案来搭建, 因为社区方案十分成熟还内嵌有 Lua 来热更新服务. 这里方案考虑采用 TCP + GoogleProtobuf 来做搭建, 这里需要注意的关键点: skynet: 主要的网络传输框架, 业务集中于 lua 语言挂载, 但请注意只有 Linux/Unix 平台. protobuf: 谷歌的序列化传输方案, 压缩的数据是常规的 JSON 的 4 倍. 这里直接导出 github 的 skynet 版本来手动编译:
    游戏架构 Created Mon, 23 Oct 2023 17:30:59 +0800
  • 游戏服务架构(四) 这篇章涉及的比较多, 可能需要做好前置的知识: TCP|UDP|HTTP相关(具体网上资料查询) 字节位编码处理(总结过) 数据大小端序列(总结过) Json|Protobuf 传输协议 Godot|Unity 至少某款游戏客户端开发就行了, 主要思路都是一致 建议如果以上都没有概念需要网上查漏补缺下, 这些基础知识基本上或多或少会遇到需要处理. 这里用 Godot 做演示, 具体 Unity 也可以去处理. Web简单游戏 单纯利用 Web 做游戏, 这种简单的游戏服务端形态在差不多 2015 年见过, 那时候用于各地 地方麻将 游戏( PS: 那时候国内游戏项目讲究快速上线, 所以诞生很多为了压低成本而速成的技术, 单纯 Web 请求做的三消游戏也是当年时代产物 ). 当年衍生很多奇奇怪怪的技术栈, 所以能够看到很多现在看起来怪异的技术选型, 而且 2015 年的时候 Websocket 还没爆发性的推广 开发游戏必须先要确定 玩法, 影射现实来说 只有确定玩法的游戏才能叫游戏, 哪怕猜拳都是得知道 '剪刀-石头-布'. 这里采用 骰子比大小 玩法这种数值对拼玩法( 戏称 '电子斗蛐蛐' ), 直接用 php+json 实现个 web 无状态服务: <?php // 解析 RAW + JSON 参数 $_PARAMS = file_get_contents('php://input'); $_PARAMS = $_PARAMS ?
    游戏架构 Created Fri, 13 Oct 2023 19:26:59 +0800
  • 游戏服务架构(三) 这里从基础的服务端开始, 主要是服务端选型和要点说明, 在广州这里我见过基本上这几种: Skyent: 最广泛的的游戏服务端, 基本上采用 Lua 编写业务 Golang/Java: 这种最近兴起相对简单服务端架构, 之前看都是不做热更而让客户端在断线重连做更新( 之前在家公司见过 Java-NIO 感觉有过度设计和启动服务直接带个2G内存占用确实吃不消 ). NodeJs/PHP: 这种 2020 年那时候兴起以 NodeJs(pomelo )/PHP( swoole/workman ) 其实差不多, 业务比较单一都是断线也是直接采用客户端连接. C++/C#无头服务器: 高性能所需的纯 C/C++ 代码编写业务, 目前看的比较多的是 Unity 无头服务让服务端挂载个游戏客户端当作主机监听转发逻辑消息. 我个人感觉 Java-Nio 这套调试最容易, 但是性能消耗及其严重 (在单机上配个 16GB 内存的时候, IDE 占用甚至开单个都卡的无比心酸, 更别说加个 Linux 虚拟机 ), 且不带 Lua 做业务编写热更新带来的麻烦导致必须重启服务. 还有我觉得Java最大问题没有像Lua/Js这种业务脚本,在做客户端业务对接没办法做到多端共用, 之前最完美的方案是客户端主程编写好 Lua 逻辑之后可以达到服务端共用地步( 有时候客户端和策划做主要对接的时候, 需要沟通策划先出大概玩法逻辑其中会直接Lua做功能演示, 后续服务端和客户端对下功能直接用就行了 ) 在我个人开来, 游戏服务端基本上可以直接集中于 Linux 端上( 基本上最后平台也只会在Linux平台 ), 无须为跨平台考虑. 而且最好比较有支持寄宿脚本语言做业务开发( Lua/Js 都行 ), 无法支持脚本业务热更新的方案在我个人看来是不合格的. 这里说下 常规语言热更新 和 游戏热更新 是两种完全不一样的概念, 常规语言热更新是监听 Linux 信号量之后做二进制覆盖启动重载, 这种情况下的程序覆盖的时候会造成中断且业务没办法无损切换, 可以思考下 socket 推送给服务端计数器 N+1 函数怎么无损不修改切换成 N+2, 并且追加 logger 打印展示( 这种情况很常见, 有些时候需要现在数据本身有问题需要动态热更新追加打印 ).
    游戏架构 Created Sat, 07 Oct 2023 13:26:54 +0800
  • 游戏服务架构(二) 这里从游戏 Web 服务开始, 一般都是作为单独部署的服务器, 有的时候会和后台管理服务放置于同台服务器. 作为游戏的 SDK 接入入口, 第三方已经将业务提取好了( 毕竟发展了这么多年, 业务都大同小异 ), 基本上只需要关注第三方 SDK 接口: Login: 第三方登录接口, 由客户端唤起之后推送到自家游戏登录接口, 我们需要做的就是数据推送给第三方验证, 验证完成就可以写入自家游戏数据库代表用户生成. PayCallback: 第三方支付回调接口, 基本上客户端唤起生成订单之后第三方会唤起支付宝/微信等方式, 支付完成会回调返回给自家游戏回调接口, 验证完成同时服务端发货即可. 注意: Web端大部分主要交互是客户端 这里游戏接口最基础两个接口( 当然如果不涉及支付可以剔除支付回调 ), 注意这里有个技巧: # Wechat 登录接口, 推荐这种接口声明方式暴露给客户端, 以 POST 提交 JSON 数据 http://127.0.0.1/v1/wechat/login # `v1` 代表了SDK版本, 这种方式让你以后接口参数变动的时候直接升级 v2 不要去变动到其他接口 # APP 更新需要这种版本更迭, 因为某些平台版本会出现参数比较多, 游戏某些方面需要用到但是很少, 所以这个可以省略 # `wechat` 代表第三方的SDK, 比如微信登录/支付登录/bilibili/抖音登录等平台接入第三方 # `login` 代表提交数据的行为, 代表需要请求登录 主要立项时候处理个登录接口就行了, 用来给手动账号密码输入即可, 后续等商务谈妥确定 SDK 接入的时候再去切换其他. # 简单的账号密码登录 请求: http://127.
    游戏架构 Created Fri, 06 Oct 2023 22:58:04 +0800
  • 游戏服务架构(一) 这里按照多年在中小游戏公司的经验衍生出来的相关架构思路和应该规避的问题, 以此游戏项目在立项的时候提前规避好问题处理. 立项选型 根据在游戏公司这么多年总结, 基本上游戏公司集中于: 传奇类: 大部分都是当年 传奇 相关类似这种滚服战力相关类. 轻度休闲: 偏向个人数值类, 内部没有和其他玩家做交互( 最多 排行榜 这种非实时 ). 重度游戏: 这种以 MMORPG 这种居多, 相对数值繁多且游戏要素很泛( 玩家间交互更多且玩法更复杂 ). 存档同步: 单机级游戏, 把存档放置与服务端同步( 客户端做业务主要处理 ), 服务端不做太多业务仅仅作为云存档类似功能. FPS同步: 没接触过的游戏项目, 中小公司可能相对比较少接触到. 传奇类这种实际上要么是 祖传代码 要么是立项的其他类似更加偏重 轻度休闲类 这种, 其实说的是那些单独从公司 ‘拿’ 出来的公用传奇源码之后需要做维护的情况. 这里开发复杂度比较麻烦的是重度游戏相关( 业务重心依赖服务端同步 ), 而最简单就是存档同步( 服务端同步状态存档文档 ). 刚开始确定立项的时候必须知道游戏项目类型, 从而能够针对性选型, 但是基本上日常方面就我在广州这边工作时间都是 skynet 一把梭处理. 基本上广州游戏公司都是 skyent, 而且底层上不需要接触导致只需要处理好 Lua 编写业务就行了, 更像是 Lua 开发者 相对轻度的 H5 平台游戏, 不考虑扩展的处理甚至看过直接采用 php(swoole) 做的简单游戏服务端功能, 只需要涵盖游戏推送邮件消息和奖励发放/排行榜等. 服务端分层 就目前游戏项目当中基本上分为: Web层: 第三方登录尽量采用简单, 基本上需要登录/服务器列表/公告基础接口.
    游戏架构 Created Thu, 05 Oct 2023 20:20:14 +0800