游戏开发

A collection of 13 posts
游戏开发

基于多级时间轮的定时器机制

4.1 原来的定时器调度机制 * 简单的轮询遍历式定时器: * 在线程循环中,每隔一定的时间间隔,调用一次OnTimer * 在OnTimer中按照管理器、对象、对象的成员等逐层遍历所有OnTimer void ThreadProcess() { while (true): { // do something... // 经过一个周期,触发定时器轮询 if (curTime - lastTime >= 750/*ms*/) { // 遍历所有管理器,调用OnTimer foreach xxxMgr: xxxMgr.OnTimer() } // do something else... } } // 管理器的定时器实现 void
8 min read
游戏开发

基于共享内存的 LOG 异步化

原有日志接口的问题 * 写日志耗时高 * 实时写入文件单行 LOG,耗时约 0.25ms(1KB 以内的 LOG 长度并不会显著的影响写入文件的耗时,固态硬盘和机械硬盘也没有显著的差异) * * 异常时日志丢失 * 缓存型日志,单文件 4K 缓存,可以极大的减少写入文件的开销,但是宕机时,可能导致文件内容丢失 解决方案 * 降低写日志开销 * 异步化 * 防止日志丢失 * 共享内存 具体实现 * 数据结构: typedef struct AsyncLogInfo_s { ASYNC_LOG_OPT_TYPE nOpt; // 操作类型 DWORD dwData2; // 自定义数据 int64_t i64Data1; // 自定义数
3 min read
游戏开发

C++代码审查终极指南

英文原文:https://www.incredibuild.com/blog/the-ultimate-guide-to-cpp-code-review-part-2 在第一部分中,我们花了一些时间讨论代码审查的广泛方面。本部分将专注于 C++,提供一个代码审查清单并提供一些最佳实践。你可以按任意顺序阅读它们,但我们建议回过头去阅读我们的之前的文章。 C++ 审查清单 代码审查清单永远不会全面,需要检查的问题、项目和潜在事项几乎是无穷无尽的。因此,制作一个涵盖所有潜在情况的清单是不可能的,而且执行起来更加困难。相反,让我们关注在 C++ 代码审查期间应该涵盖的广泛方面。 类别 1 - 需求和底层领域的理解 Joel Spolsky(Stackoverflow 的联合创始人,Fog Creek 的创始人,现在是 Glitch 的创始人,以及Joel-on-Software
19 min read
游戏开发

账号服务器开发总结

从六月份开始开发账号服务器到今天,账号服务器的大体功能也算完善了,账号服务器的开发暂时告一段落,预计下周又回去开发游戏服务端了。 一直想写一篇文章总结一下账号服务器开发过程的经验和教训,迟迟没有时间动笔,今天正好借这个机会写一下。虽然不是什么高大上的东西,但是我们的项目还在运营,另外也有商业秘密的原因,设计到具体实现细节的这里不会描述,也不用来问我,我也没法告诉你。 起因 公司本来已经有了一套比较成熟的账号服务器了,不过一直是端游在用的。而我们是手机游戏,许多需求和端游不同: 1. 手游常常需要接入各个第三方渠道 2. 登录验证方式不同,手游的第三方渠道账号登录以后需要通过HTTP协议到第三方平台进行账号验证 3. 手游有混服登录的需求(即多个第三方渠道的账号登录同一台游戏服务器) 4. 原有账号服务器掌握在别的部门手上,每次功能修改和开发都需要耗费大量时间沟通协调,自己开发维护响应会比较迅速 虽然有这么多需求,早期我们也没打算自己开发账号服务器,而是在游服上直接做,然后用一个数据库对账号进行重新编号排序。这种做法,在内测阶段只有一两台服务器当然没有太大问题
9 min read
游戏开发

游戏服务端死循环检测方案

传统死循环问题检测排查的困境 游戏服务端开发维护过程中,经常会碰到死循环或者游服性能问题,此类问题一般存在本机或者QA内部环境极难重现,难以定位和排查的问题。一般能采用的方式,只有: 1. 静态代码审查 2. 在可能出问题或者可能耗时较多的代码部分添加LOG,然后经过测试后上线观察,再加LOG,再观察。 以上这些传统方案不仅定位效率低,准确度低,而且问题的解决周期长,碰到影响恶劣的问题,还可能引起重大项目事故。 本方案解决的问题 1.实现精确到功能点级的故障定位,极大缩短了定位问题的时间。一般故障报出以后,当下查看LOG即可定位到问题所在。 2.实现精确到功能点级的耗时检测,和函数级的LUA脚本函数调用检测,并从时间段累计调用次数,累计调用耗时,单次调用平均耗时等方面综合监测性能问题,检测时间精确到tick。 方案应用后极大的提高外服死循环和性能问题的排查效率,目前已通过该方案查出数个死循环和性能问题。 实现方案 游服的业务驱动,一般来自这么几个部分: 1.
5 min read
笔记

导航网格学习笔记

相关资料 1. 导航网格开源库:RecastNavgation 2. 一个基于C#的AI库,包含UNITY 3D插件:CAINav 3. 开源服务端框架:kbengine 4. WOW服务端模拟器:TrinityCore RecastNavgation是业界比较知名的导航网格生成和寻路的开源库了,大名鼎鼎的UE4和Unity3D游戏引擎都有基于Recast的实现,而上述两个开源服务端框架中,导航网格也是基于Recast的。因此,Recast应该是已经被证明可靠的导航网格LIB。 在CAINav官网看到有比较详尽的导航网格文档,因此打算深入了解一下导航网格的原理和相关算法,本篇就是学习过程中记录的学习笔记。 多边形网格(Polygon Mesh) 多边形网格(Polygon mesh)是三维计算机图形学中表示多面体形状的顶点与多边形的集合,它也叫作非结构网格。这些网格通常由三角形、四边形或者其它的简单凸多边形组成,这样可以简化渲染过程。但是,网格也可以包括带有空洞的普通多边形组成的物体。 导航网格的生成 1. 高度图介绍 * 基本高度图结构
8 min read
想法

一种回合制战斗过程的记录方式

回合制战斗的页游,需要将战斗过程在服务端全部计算完成后再下发给客户端,并且还需要将战斗过程保存起来,让第三方直接查看。 将战斗的过程以动作为单位分解成多种消息,之后将多种战斗消息封装在一个消息打包器中下发给客户端。客户端从打包消息中按字节流的方式还原 出战斗消息,再解析消息进行表现。保存战斗过程只需要保存被打包完的字节流消息即可。 MsgPacker #pragma pack(push, 1) typedef struct { MSGHEAD_DEFINE USHORT usAction; DWORD dwData; DWORD dwAmount; //后面有几个消息 UCHAR ucMsg[0]; //各种战斗消息 }MSG_Info; #pragma pack(pop) ```**MsgBattle**``` enum MSGBATTLE_ACTION { MSGBATTLE_None, = 0, //无效 MSGBATTLE_BattleStart = 1, //战斗开始 MSGBATTLE_BattleEnd = 2,
2 min read
游戏开发

一种可以守护多个程序的守护进程的实现方案

* 账服需要守护程序,原来的守护程序使用的一对一的方式,技术部希望我们能提供一对多的守护程序,这样他们可以不用区分哪个程序守护哪个账服,多开时比较方便。 * 原来的守护进程的做法是先启动守护进程,然后守护进程通过CreateProcess启动账服程序,然后调用WaitForSingleObject挂起等待账服进程,如果返回,说明账服崩溃了或者被关闭了,那么就重新启动账服,不断循环。 如果一个守护程序要同时守护多个程序,那么原来的方案就适用了。 * 于是我们采用了另外一个方案: 1. 在文件中配置需要守护的所有程序 2- 每隔一段时间(可配置在文件中,如5秒),遍历一次所有进程(可以使用ToolHelp32也可以用enumprocesses),获取进程的可执行文件的完整路径文件名,和配置内的程序进行匹配 3- 如果无法找到,则重新启动这些程序 * 方案优缺点分析: *
1 min read
游戏开发

RakNet参考手册索引

RakNet开源免费了,接下来准备学习一下,计划把RakNet的文档做个翻译。就从手册开始吧。原文链接。 介绍 手册最后更新时间 2012-11-19。 查看readme.txt文件获取当前版本号。 RakNet是为游戏或者其他高性能网络应用设计的一套高性能的网络API。 RakNet致力于提供现代游戏所需的绝大部分的功能特性,如Master Server(主服务器),autopatcher(自动更新),语音聊天和跨平台兼容性等。RakNet当前支持Windows, PlayStation 3, XBOX 360, PlayStation Vita, Linux, Mac, the iPhone[1], Android,和Windows Phone 8。 快速入门 多人游戏的组成 系统概览 实现细节 教程 编译设置(Visual Studio) 编译设置(XCode) 可选的第三方依赖项 操作方式 教学视频 介绍:
8 min read
游戏开发

Lua语言学习笔记

自学过Lua好多次,每次都因为长时间没用然后忘记了。这次决定做一下笔记,一方面加深印象,另一方面为了下次忘记能够快速“捡回来”做准备。 参考教程:菜鸟教程之Lua教程 参考手册:Lua5.3参考手册 斜体部分为我个人的理解,可能不一定正确,只是帮助记忆。 [TOC] 注释 单行注释 --是单行注释: --这是单行注释 多行注释 --[[]]--是多行注释: --[[ 这是多行注释的第一行 这是多行注释的第二行 ... ]] 标识符 我喜欢称之为变量名。规则同C/C++。字母或者下划线_开头,后面跟字母、数字或者下划线。 关键词 即系统保留关键字。一般约定,以下划线开头连接一串大写字母的名字(比如_VERSION)被保留用于Lua内部全局变量。 and break do else elseif end false for function if in
45 min read
游戏开发

3D地图和场景管理

其他项目的做法 * 方案 1. 将场景用八叉树划分,最多三层 2. 物体根据坐标直接加入八叉树的叶节点(忽略了体积和包围盒) 3. 移动采用完全相信客户端的做法 4. 通过MoveState来记录移动过程,客户端上传开始位置、结束位置、持续时间信息,服务器根据开始位置和结束位置、以及时间计算出速度。 5. 只有在其他对象主动查询或者RegionSwitch的OnTimer时候,才会做移动,八叉树节点切换 6. 如果没有主动查询,中间过程是没有体现的 * 疑问 1. 如果出现网络延迟,客户端中途改变移动方向或者目的地点时,两端的位置会有严重偏差,这时如何同步? 2. 如果地面上有陷阱,在起点和终点之间,是否会被触发? 3. 忽略了体积的情况下,如何做碰撞检测? TrinityCore的做法 TO-DO 我的想法 1. 场景用八叉树管理,在八叉树中只保存动态物体,如玩家角色、NPC、怪物、子弹等,姑且称为动态检测。八叉树可以用来做广播和碰撞检测,
3 min read
游戏开发

3DMMO游戏服务器架构

服务器框架 备选资源 1. NavMesh 2. 3D碰撞检测 3. 网络通信 * 连接协议 * RakNet * ENet * libuv * 消息协议: * ProtoBuf * MsgPack * BitStream:RakNet集成 网络通信协议的选择 * 结论:由于客户端最后选择了UNITY3D引擎,所以有些选择考虑到客户端的实现做了妥协。最后选择了libuv+byteStream,并且自己做了一层封装,起名为UVSocket。代码我提交到了oschina。 代码库:UVSocket * 原因: * 首先,如果不考虑客户端,我的首选会是RakNet,毕竟是老牌的游戏通信库,而且UDP从延迟角度来说也更适合用于网络游戏。并且收发包没有分包合包的烦恼。但是RakNet并没有官方的C#实现,因此客户端担心和
4 min read