动态加载资源

如今很多游戏engine宣称自己支持动态加载地图,也就是说可以作到跨地图时的零读取时间。听起来很高深的技术,实际不难实现。最近我正在考虑更加通用的解决方案。

先说说基本的思路。也就是我们需要把地图数据切割成小块,让每一块的数据读取解析量并不太大。然后,就可以根据玩家所在坐标读取最小数据量的数据。当玩家移动的时候,利用一些机器闲置时间去读周围的场景,或者进一步可以根据玩家移动方向把前方数据预读的优先级别调高。

其实,这个方案可以被推广到所有的游戏资源。其实,我们可以给每个资源文件都放置一个通用的数据域存放一些建议关联文件列表。如果是地图块的话,它的建议依赖文件就是它周围的地图块,或者是人为设置过跳转点的目标块。

而模型文件则可以把它依赖的贴图,骨骼文件做为建议依赖资源。地图场景文件可以建议依赖一些摆放在上面的模型文件。

有了这些依赖关系,我们在读取某个指定资源文件后,可以用一个独立线程预先加载一些可能下一步要加载数据,也可以由逻辑层主动通知一些预测信息。例如我向东向移动,可以通知 I/O 线程,东边的相关资源优先级别高一些,I/O 线程则去调整预读队列的次序。

I/O 线程的设计是比较复杂的,我的最初想法是建立一个大的 , 以内存页对齐(IA32 下是 4K)。如果数据被预读了,主线程索要数据的时候,用共享内存的方式,将 中的数据块交换出去。

经过和同事的讨论,一个做 OS 的同事提示我,设计可以更简洁一些。因为现在 OS 对 file I/O 的 cache 机制都非常完善了,预读只需要去真的读一下文件即可,不需要再去自己做 cache,自己做 cache 只能节省一些数据 copy 的操作,但是其逻辑的复杂程度还有页表操作的负担不一定划算,所以我们只用专心做好预读逻辑即可。

这样的动态加载的资源管理模块,完全可以做的对主线程完全透明。我们的主线程只需要按阻塞模式去读取文件就够了。

但是,如果读取文件还伴随着耗时的解码过程。比如解 jpeg,,解密。那么我们最好自己做 cache 了。

标签Tags:, , , , , , , ,

游戏,一种奇怪的软件

程序是可以调试的,可以用工程的方法做质量控制,可以有测试的机制。大多数时候是可以被验证的。而且掌握了正确的方法,我们可以一步步的把程序搭出来,逐步看到成果。

但是游戏,作为一种软件则不然。

首先,游戏设计中,多出了一个游戏策划的概念。往往,一个大型的游戏还不只一个人,而是一组人。而平常做软件,尤其是小作品,往往是实现的人是第一用户,在构思怎样让软件贴近用户。(我个人认为,游戏软件还是属于一种规模不大的小作品)作为游戏策划仿佛漫无目的在想在写。却在构思和实现之间断了层。而且文档这种东西是无法量化的验证并做质量保证的。

其实,把思考建立在一个高的层次而不必理会低层次的机理并非坏事。单从写程序来讲,一个 程序员可能永远不用关心 本身是怎么实现的,他的程序是如何转换为机器代码,运行于 CPU 的。相反,一个好的 C 程序员刚刚转写 的时候,通常不会是一个好的 程序员。这种以高层次为基础来发展的东西,更多靠的是经验的总结和学习,而非理论和逻辑的推理。(当然从更高层面说,有了足够的经验总结后,更宏观的工程,可以从这些微观的经验上基于逻辑推理来描述)

游戏策划估计也是这样吧。所以游戏策划更依赖一个成熟的团队,和技术基础。人的思维空间是有限的,思考深度也是有限的。有了一个牢固的根基后,才有发展的深度和广度。

标签Tags:, , , , , , , ,

思维的惯性

BUFF 这个术语是现在网络游戏中非常常见的。给角色加一个 BUFF 通常意味着对虚拟角色的一些数值上的临时修正:例如,攻击力 +5 ,防御 -10% ,速度加倍,等等。

玩过魔兽世界的朋友应该很容易理解这些。通常游戏里的 BUFF 设定比我上述的例子更加的复杂。

这里不谈游戏设定,谈谈实现。 (更多…)

标签Tags:, , , , , , , , , , , ,

游戏中的货币

究竟如何用游戏规则来稳定虚拟货币。

首先,我认为现在的网络游戏中,货币并不完全等同于现实社会中的货币。现实社会中,货币只是一种能直接起交换手段或支付媒介作用的东西,它本身没有价值;货币的投放由央行控制。但在大多数网游中,货币本身有了实用价值,它可以从系统那买到各种补给品,或是可以直接增加虚拟角色的能力。而且货币本身也多由玩家自己的主动行为生产。

同时,在健康的虚拟经济环境中,虚拟货币也起到了现实货币同样的作用——作为支付媒介。 (更多…)

标签Tags:, , , , , , , , , , , , , ,

游戏服务器内的组播

游戏服务器在设计时,会有许多组播的需求。比如一个 NPC 需要向周围的观察者播出它的状态信息。无出不在的各种聊天频道中需要向频道中的参于者广播聊天消息等。

通常,我们会为每个组播的请求维护一张列表,然后再把需要的信息包发送给指定列表上的多个连接。这个过程在很多地方都会遇到,一个设计的不太好的引擎,再这里有可能滋生诸多 bug 。尤其在多服务器的设计时尤其如此。

这两天,我试图寻找一种简洁统一的解决方案。

前几天的一篇 blog 讨论了一组服务器设置多个外部接入点的设计。就着这个思路我们可以引申一下。

当每台连接服务器设置一个不大的上限,比如最多同时处理 8192 个外部连接,那么管理分组倒不会带来太大的负担。

我们只需要在逻辑服务器与连接服务器间定义四条协议。

把一个连接加入指定分组。
让一个连接退出指定分组。
向一个分组广播消息。
删除一个分组。
这里,后两条协议是冗余的。

对于第三条协议,如果表示连接号的容量足够大,我们完全可以留一部分号码用于组播。这在 IP 协议中定义 IP 地址的构成时就是用的类似方案。不过我们的设计为了节省带宽,全部用的 2 字节做内部连接号,资源比较紧张,所以就单独设计一条协议了。

对于第四条协议,当最后一个连接退出时,分组就自然取消了。增加一个专门的删除协议,纯粹是使用上的方便。

在连接服务器上维护一个分组,仅仅需要一个 1K 的数组(8192 bits)。而有组播需求时,只用遍历这个数组。在 32 位系统下,只是一个 256 次的循环而已。因为大部分分组的成员都不会太多。数组中充斥着大量的 0 。扫描一下就非常的快了。

连接服务器用一个简单的 freelist + hash 表的技术,就可以高效且动态的管理不限量的分组,无论从 CPU 还是内存的负载来看,都是可以接受的。

我们额外需要做的只是一个分组编号分配管理器。为每个进程分配唯一独立的分组号就够了。在我们现在的设计中,为了尽量避免交互通讯。分配新组号采用不需要反馈的形式。每个需要申请组号的进程,都有独立的组号 id 空间。由分组管理器对若干独立的分组号做一次统一映射。

换句话说,每个服务器进程都可以直接从 0 号分组用起,然后直接用 1 号,2 号,3 号 …… 类似操作系统管理物理内存一样。独立进程拥有的只是虚拟分组号,由管理器映射到全局唯一分组号上。这样就完美的解决了不同服务器进程间的分组编号冲突问题。

标签Tags:, , , , , , , ,

多服务器的用户身份认证方案

当游戏服务器群达到一定规模后,让用户只从一个入口连入会给这个入口带来很大的压力。这样,我们就需要让服务器群中的多台机器都允许用户直接连接。

当服务器开放给用户直接登陆后,必须面临的一个问题就是用户身份认证的问题。

大多数提供网络服务的公司都做了一套统一的用户认证系统,比如微软的 passport ,网易的通行证,等等。为了避免重复验证用户身份而给用户认证系统带来过大的负担,云风在这里给出一个参考解决方案。 (更多…)

标签Tags:, , , , , , , , , ,

随机数有多随机?

作为一个常识,每个程序员在做入门学习时,都会被老师谆谆教导:我们用的编程语言中的随机函数,只能产生出伪随机数。它有它的内在规律,只能作为对显示世界的随机事件的近似模拟。接下来,我们通常会被传授随机种子的概念。以及用物理上更随机的量做种子。比如系统时间、两次敲击键盘的时间间隔、多次移动鼠标的偏移、甚至系统出错的出错信息码等等。

作为游戏数值策划,除了加减乘除,用的最多的数学概念恐怕就是随机数了。有经验的数值策划或许从他的前辈那得知计算机中程序产生的随机数并不太可靠;或者他本身就受过程序方面的训练。如果游戏项目更幸运一点,担当数值策划的他是一个数学爱好者,并读过诸如《计算机程序设计艺术》这样的技术书籍,那么事情会好的多。可惜大多数境遇下,策划们从不深究计算机随机数背后的细节,也不太关心所谓“伪”随机数究竟“伪”到什么程度。 (更多…)

标签Tags:, , , , , , , , , , , , , , , , ,

角色动作控制接口的设计

本质上,图象 engine 是一帧帧渲染角色精灵的。渲染这个操作必须被隐藏起来为应用层不可见。3d engine 有更高的表现力,比如可以做骨骼动画,以此做动作间融合。这些应该归到渲染层面做。绝大多数情况下,应用层不应该关心。

以前,我们的引擎接口提供了方法设置角色当前应该播放的动画系列。其参数有播放指定次数还是循环播放。仔细考虑,其实不太合理。 (更多…)

标签Tags:, , , , , , , , , , , , ,

MMO 的排队系统

大家都说 MMO 里的排队系统是魔兽世界的首创。可是只要是有社会经验的人,一拍脑袋就能想出这个点子来。谁都知道,在大量人拥挤在一起想完成同一件事情时,排队遵守次序是提高整体效率的最佳方案。那么,为什么 MMO 发展了那么多年,只到 wow 才被用于玩家登陆? (更多…)

标签Tags:, , , , , , , , , ,

游戏的帧率控制

我曾在不同场合,多次向人表达我对游戏程序设计的一个重要观点:时间控制,对于游戏程序设计至关重要。

这是因为,大多数电子游戏,都是一个实时人机互动系统。在非人机互动的软件中,软件及硬件一起是一个封闭系统,时间参数对这个系统是否正确工作是无意义的量。这样的系统,我们尽量应该设计成自动化工作模式,只要有正确的输入,得到正确的输出即可。通常,这样的系统的开发,还应该有自动化测试的流程去驱动它。

但实时人机互动软件则不一样,我们得把人看成系统的一部分。人和机器的交互是通过人眼、人耳、键盘、鼠标等完成信息交换的。如果把人脑看成一个线程、计算机看成另一个线程,我们几乎没有能力实现一个资源锁,利用锁的方式保证系统工作永远正常。人脑在全速运转时,适时得不到正确的信息输入,整个系统就可认为出现了故障。

可见,在这样的系统中,时间控制显得多么的重要。 (更多…)

标签Tags:, , , , , , , , , , , , , , , , ,