Main

July 27, 2008

把 AOI 的部分独立出来

应该是在 blog 上第 2 次讨论 AOI 的问题了,另外还要算上一篇写完没有公开的。

昨天刚出差回来,晚上跟前大唐的服务器主程聊了一下。扯到了 AOI 的问题,我提了个分离这个模块的方案,在此记录一下。

AOI 主要有两个作用,一个是在服务器上的角色(玩家或 NPC )做出动作时,把消息广播到游戏地理上附近的玩家。当进程中负责的玩家不是很多的时候,可以直接对整个进程内的连接广播。这样的处理最简单,随着硬件的提高,可能是未来的主流方法。但是目前,为了减少处理的数据量,尤其是带宽,我们通常需要 AOI 模块裁减一些数据。

第二,当玩家接近 NPC 时,一旦进入 NPC 的警戒区域,AOI 模块将给 NPC 发送消息通知,以适合做一些 AI 的反应。

July 20, 2008

一个简单的寻路算法

周末跟同事聊天,问了一下最近公司新项目的一些需求。发现现在无论是玩家还是策划,纷纷要求引擎可以实现自动寻路。虽然我对此不以为然,但其实这也不是什么难题,打算随便做一个好了。

我们现在的 engine 是用矢量线段描述场景中的障碍的。这些线段无所谓人工标记还是从场景模型中自动生成出来,又或者是用传统的打格子的方法变换出来。在这些障碍线构成的矢量场景中寻路其实不是什么难事。

我们只需要在场景中标记出若干 waypoint ,这些 waypoint 一般在大片无障碍区域的中央,以及分叉路口。游戏中故意设计迷宫为难玩家绕来绕去又没有什么玩点内容在里面是没有什么意义的。(除非是“不可思议的迷宫”这种以迷宫为重要玩法的游戏)所以,大多数游戏场景,路径的拓扑关系复杂度非常有限。 waypoint 靠人工设置就足够了。

btw, 自动生成 waypoint 也不是难事,反正这个东西不会是性能要点,机器生成 waypoint 不会比人工设置的糟糕太多。算法就不展开谈了。waypoint 的设置要点是:场景中所有可达区域都能看到至少一个 waypoint ,这个要求可以用程序检测。

我们把所有 waypoint 间可以直线连接的线路连起来,得到一张图。可以预存下这张图,以后的工作则非常简单。

June 24, 2008

摄象机接口的设计

最近在调整 3d engine 的接口。前段时间把 GC 模块加到底层后,很多部分都需要修改实现了(可以简化许多实现代码)。既然重构代码,不如就再次审查一遍接口的设计,结合最近的一些想法,重新弄一下。

嗯,那么 3d 引擎是什么?跟 3d api (Direct3D 或 openGL)有什么区别?固然,engine 如果只是做 3d api 的一层薄薄的封装,抹平各套 3d api 的差异。那么,就过于底层,显得小了。

如果为特定形式的游戏写死代码,让开发者写一些 MOD 插件就可以形成不同的游戏,那么又显得太高。在这种高层次上,游戏类型会限制于 engine 的实现。比如魔兽争霸 3 就直接用户写 MOD ,并的确有人以此发展出许多玩法。但你永远不可能在 魔兽争霸 3 的基础上写一个 MOD 实现第一人称射击游戏。

所以我指的 3d engine ,是处于 3d 游戏软件结构中间地位的东西。

那么,我们的 3d engine 到底要解决的是什么问题?做 engine 绝对不是以我能在 3d api 的基础上扩展出什么东西为设计向导。因为,对于完成一个软件,是一个从机器实现域映射到问题域的过程。这两个领域的模型是不同的。3d api 完成的是实现域的扩展,engine 则应该完全从实现域到问题域的一个变换,让开发者可以用最接近问题域的语言来表达问题。

May 31, 2008

3d 引擎中对场景数据的接口设计

目前是我第一次设计 3d engine ,虽然主要贡献 3d 方面代码的同事不是第一次做了。我们做了两年多,大方向上是我在把握设计。但是毕竟是没有什么经验,也就老在修改。

这个周末再审以前做的东西,觉得接口上还需要调整一下。比如精灵的控制接口、摄象机的控制接口、场景描述的接口等等。以一个游戏开发人员的角度来看,我需要接口是什么样子的?

我希望是最方便的描述虚拟世界中各样东西的相互关系,引擎当隐藏住不必要的细节,比如 3d 方面的数学知识,专业化的术语,复杂的坐标转换等等。今天写下这些,不是定论,而是做些思考的记录。

我想知道,对于 3d 引擎的使用人员,如何描述虚拟场景,暴露出怎样的接口是比较合适的。

May 23, 2008

关于 openGL 的 4444 贴图

我们在实现游戏界面时,用了一张 RGBA 4444 的贴图做 buffer 。最近同事测试效率时总不满意,发现上载 4444 贴图时,openGL 表现出来的性能实在是太差。(显卡为 ATI X300 ,最新版驱动)

几个人一开始怀疑是显卡或驱动程序的缺陷,进而想换总做法,不用软件渲染界面的方案。改把界面元素全部放到显存里。前几年,我为天下二设计界面的模块时,也有同事有此疑惑,编写代码做过比较。记得当时的结论是:仅仅从性能角度上考虑,把界面所用资源全部放到显存里,并不能提高太多速度(反而可能性能更低)。当时用的 Direct3D 做底层,似乎没有今天遇到的问题。

May 07, 2008

数值调整、模拟器、编辑器

最近做游戏数值有点头大。也研究了一些游戏的设定,有点心得。举个很小的例子来谈谈:

wow 里的护甲对物理伤害吸收是乘一个百分比的,其公式为:

min (护甲/(护甲 + 400 + 85 * 敌人等级) , 0.75)

怎样理解这样一个公式的内在含义?为什么会设置成这样?

May 01, 2008

那些日子(二)

我在北京生活了半年。接触北京这个城市要更早一些。大约 85 年的时候去过,一周时间几乎玩遍了北京所有的景点。小时候的记忆特别美好,我在那个时候爱上了北京。记忆中,天安门广场是那么的大,紫禁城的宫殿如此雄伟…… 以至于回到学校时,不知道用怎样的形容词才能形容。

10 多年后,我在学校的机房上网,泡 bbs ,做个人主页,写一些关于游戏的自己的想法。交了许多的网友。大家都是业余的,年轻气盛,想自己做出好玩的游戏。王欣是第一个给我发 email 的职业游戏人。更早的 97 年,国内有两家大的游戏公司,前导和腾图,有如台湾的大宇和智冠。可惜生不逢时,前导做不了大陆的大宇,腾图也远不及智冠。

腾图命中注定的散掉,王欣的八爪鱼工作室从腾图分的出来。98 年,王欣邀请我在假期去北京玩,他把我带进游戏这个圈子。我又有机会站在天安门广场,原来并没有那么大。我想,如果毛泽东纪念馆挪一下地方的话,广场会更宽广一些,和我儿时记忆中的一样。小时候怎么就没这种感觉呢 :) 。

那个年代,我成月成月的逃课,去北京帮王欣做些兼职工作,并听他说些早年北京游戏圈子有趣的八卦,有如今天我给新人说起往事。回忆起来,自己其实什么也没做,似乎又做过点什么,反正最后一次,我拿了一小笔兼职工资。不过没有花掉,因为回到学校的时候,一个同班同学缺钱交学费,我全部借给了他,毕业那天他才凑起来还我。

当然,身在北京,我就有机会四处拜访网友同好。随即发现,其实许多网友都已经专职在做游戏了。有些人后来再没怎么联系,比如曾经在金洪恩做《自由与荣耀》的 3d engine 的 riso ,我还记得他在那个晚上,他抱怨他的后继者让代码从几万行膨胀到十几万;又比如做《独闯天涯》的郭巍,他念叨过来北京前没有钱吃饭,小组里每个人一个冷馒头就可以啃一天,脑子里只想着把游戏做出来 ……

两个很重要的朋友,也是在那段时间见的面 —— 余雪松和吴东黎。我们通过在网易个人空间(当时叫 N-SPACE)交换链接认识的。他们搭档了很多年(直到今天),经历很传奇。

April 30, 2008

那些日子(一)

明天就是五一假期了,同事都已放假。我不打算在假期加班,因为加班也无事可做,手头上的工作都需要与人合作。

前几天和新同事吃夜宵,大家聊的异常兴奋,我也忍不住开始想当年。当年那些美好的日子,记忆已经很模糊了。我想再过个两年,估计我都不能准确回忆起那些曾经对我影响深刻的日子准确的时间。是时候记下点什么,对自己是一种纪念。

我这人有个优点,选择性记忆,那些不快的回忆很容易随风而去。活在我记忆中的人们,对他们只留下感激。我也曾经爱写日记,很早我就写电子日记,记在自己的机器上,PDA 上,当我有一些不愿意再回忆的事情时,我会个将整个文件加上密码,长长的一次性密码,保证自己只能记住一小段日子。当这段日子过去,密码就消失在记忆中。然后再也打不开这些文字,等到下次更换硬盘,无论我多么的想再看一眼当年的自己,也无能为力,只好把加密过的文件删去。

我想我就是这么成长过来,没有什么挫折的感觉被反复咀嚼,都已经抛在脑后。生命中没有什么不可以失去的,这个道理很早就明白了。我曾经懊恼过丢失了大量的源代码、自以为写的不错的文章、早年的聊天记录、珍贵的日记、数年的电子邮件…… 最后我明白了,一切的一切不过是身外之物,我能拥有回忆中最美好的部分,那么已经是特别幸福了。

不过也正是如此,以下的记录也只能是我努力的回忆。或许因为时间久远,跟真实有所偏差,或许从我的角度只看到的事物的一面,但是、我可以保证,并没有故意在叙述中掺差虚假的东西。

是的,我想讲一个真实的故事,一个拥有数千万玩家的游戏诞生的故事。我并不喜欢这个游戏系列本身,但是我为这个产品自豪。我的代码曾运行在几千万用户的机器上,作为一个程序员,还有什么比这更让人满足的呢?也许有,比如让这个用户数量再扩大 10 倍。

April 27, 2008

游戏数值公式的表象与本质

周末、睡的比较晚,起的也比较晚。总的来说比平常睡眠时间长一些,所以到了这周一的第一个小时,我还是全无睡意。随便写点什么,关于游戏的,关于游戏设计方面的东西。

鉴于我在游戏设计领域还没有什么建树,远不如游戏程序设计方面有发言权。甚至对游戏设计说三道四的话,还不如在软件开发上乱侃几句有分量。在下充其量也就是个没吃过猪肉天天能见着猪跑的家伙,如果有猪肉已经吃腻味的方家读到这里,请一笑了之,别跟我一般见识。

本来在本文成文前打的腹稿中想举出些实际的例子来,可是发现怎么都会或多或少的得罪圈子内的策划朋友。罢了,只说些空话好了,算我做了半个月游戏数值,闲暇时发的点牢骚。

从为我们的游戏设定角色基础属性,以及设计战斗伤害的计算公式开始。

April 21, 2008

不那么随机的随机数列

曾经看过这样一种赌徒的策略:假设在一场赌大小的赌博游戏中,赔率是 1:1 ,而庄家不会出千,开大和开小的概率均等(皆为 50%)。赌徒一开始压一块钱,如果他压错了,那么下一次就压两块,再错继续加倍。一旦压对,赌徒永远可以保证有一块钱的进帐。并且从 1 块钱重新开始。

看起来,这种策略能保证永远包赚不赔。但实际上为什么没有人用这个方案发财呢?

放到现实中,试图采用这个策略去赌博的人,几乎都会赔的倾家荡产(当然只要是赌博,差不多都是这个结局)。不要怪运气,不要怪庄家出千,因为这个策略从一开始就注定了失败。

April 10, 2008

游戏的帧率控制

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

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

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

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

April 06, 2008

负反馈系统在模型动画控制中的应用

最近在解决 3d engine 接口的一处设计问题。我们知道,在 3d 游戏中,engine 的接口设计往往比性能更加重要,这决定了 engine 是否好用,甚至是否能用。简单的功能堆砌不是 engine 。

目前我想弄清楚的一个技术点就是,当模型置入场景后,如果播放的动画本身有位移,引擎应提供怎样的接口,让使用者最为方便的表达他意图。

具体到一个问题点来说,当我们的美术人员制作了一组四足动画奔跑的动画后,怎么在游戏中最自然的表现出来。

就我有限的眼界所知,有许多人在制作 3d engine 时是这么规定的:美术需要把动画调整成原地奔跑的样子。(或者换个方式,在从制作软件中导出时,让原本具有位移的动画变为原地移动)如此,就可以在最终表现时,自由控制播放的速度。

但是稍加思考,就知道这样做导致的图象表现和我们期待的样子是有偏差的。下面让我们来分析一下。

March 15, 2008

基于 lua 的热更新系统设计要点

很久没写 blog 了,主要是忙。项目排的很紧,一个小项目上线,发现不少问题,所以把多余精力都投进去了。最后人手不够,亲自上场写代码。在不动大体的情况下,最大能力的修改了一些设计,并把能重写的代码重新写过了。

这一周,写了三天半程序(其中通宵了一次)。平均每天写了千多行程序。基本上把原来项目里用的几万行东西替换下来了。重构总是能比老的设计更好,不是么? :) 不过这事不能老干,个人精力再充沛。故而还是找到称心的合作人比较好,也不能啥都自己做啊。程序员的效率差别可不只十倍二十倍的差别这么少。btw, 前段时间通过这里找到的新同事不错,呵呵。如果有缘,还想再找一个能干的。我相信,聪明人在一起做事可以获得更多快乐。

闲话扯到这里,总结下这两天做项目的一点经验。那就是:当我们需要一个 7*24 小时工作的系统时,实现热更新需要注意的要点。当然,这次我用的 lua 做实现,相信别的动态语言也差不多。只是我对 lua 最为熟悉,可以快速开发。

March 02, 2008

MMO 的排队系统

这两周那是忙的天昏地暗。都是些琐碎的事情,两个项目的。理理代码,发发邮件,打打电话,改改 bug ,开开会,签签字,写写报告。周末也加了一天班,工作居然是安装一个论坛系统,外加修改 css ,以及修改模板,调整版面。没办法,时间紧,人手少。

btw, 在服务器上装 php 时,因为开始 ports 没有更新,出了好多问题。mysql 一开始忘记装 gbk 的支持,困扰我老半天。鄙视一下公司购买的某著名 php 写的论坛系统,居然默认不是用 utf-8 编码的。

闲话扯到这里,今天想谈一下上月底,四年逢一次的好日子里,我们公司憋了好久的《天下2》终于又一次体验测试的事情。

February 19, 2008

角色动作控制接口的设计

最近一段时间工作的侧重点转移,我从服务器的设计转到客户端这边来。

自从最底层引擎的架构完成后,我们的客户端留了两个人在全职写代码,一个人负责 C 层面的 3d engine ,另一个人负责设计高层面的应用接口,并在此基础上完成游戏 demo 。

从程序员角度上看,人都是相当不错的。要设计有设计能力,有编码有编码能力。代码审美观上大家也很一致,所以我们几个人一起工作的很愉快。

唯一美中不足的是,做 demo 的程序员游戏接触的太少,所以在操作手感调整方面有点相形见绌。需要经常性的跟负责战斗动作系统的策划沟通调整。而策划毕竟不太明白程序背后再用怎样的方法实现,最终还是有点不尽人意。如果有足够的时间,倒总是能调整好。不过现在项目进度比原来计划有所提前,我就直接参于进来参合了。加快这方面的开发进度。

上周花了几天时间通读了所有相关的代码,整体设计还是不错的。不过这两天用下来,还是觉得有点别扭。

我希望游戏能有比较流畅的操作感,可以灵活的操作游戏角色做出各种动作,包括战斗时的腾挪,组合技能等。写了不少脏代码尝试我希望的手感时,终于发现一些设计问题了。

February 17, 2008

键盘毕竟不是手柄

周末在写 demo ,为了给同事示范我希望得到的操作手感。作为一个能写点程序的游戏设计者,自己随时实现出来看看恐怕是不可多得的优势了。

我们的游戏有一定的动作成分在里面,所以我不想采用鼠标控制角色的行动,以对拍砖头的形式表现格斗场面。本质上我更偏好 console game 和游戏手柄的操作感。不过在 PC 平台上,手柄并不普及,只能在最普及的输入设备——键盘和鼠标上下点工夫了。

手柄控制方向主要有两种:

其一是模拟杆,在 PSP ,PS ,Wii 等手柄上均有安装。好处是至少可以感知两级力度,并可提供非常细的方向信息输入。控制游戏角色行动时,操作感很不错。

鼠标通过移动可以提供方向信息,甚至通过移动速度可以模拟出力度的差别。但毕竟鼠标缺乏力的反馈,且必须通过移动才能提供信息,本身不能保留状态(鼠标的 button 可以提供状态,所以很多 fps 把前进操作设置在鼠标的按键上),和手柄的感觉还是差了很远。

btw, IBM 的 TrackPoint 如果特别针对去开发,其实是个不错的游戏输入设备,可惜还是太专有化了。

其二,就是类似任天堂的十字键。由于有专利,到别的厂家那里换成了其它形式,不过大体还是差不多的。这类设备可以精确的输入八个方向,在格斗游戏中用的最多。比如我的最爱 VF4 EVO 的 PS2 版,干脆就禁止了模拟杆的输入,只允许用八方向键。

对应到 PC 上,大多数游戏用 WASD 四个按键模拟这个设备。不过要小心的是,由于键盘硬件设计的缘故,大多数键盘处理三个以上按键同时按下时,会发生所谓锁键问题。比如我的 DELL 键盘,同时按下 W 和 D 键后,再按 E 键,系统就接收不到 E 键的消息。这类情况试硬件决定,不同键盘处理能力不同。据说有比较强悍的键盘可以处理任意 7 个按键同时按下的消息,我就没有试过了。

好在现在的键盘处理两个按键的能力还是绰绰有余的,用 WASD 模拟八个方向的输入足够了。

November 30, 2007

讲稿

如果不出意外的话,我现在正在准备在 2007软件开发2.0大会 上的一个演讲:大世界网络游戏服务器的构架 。马上就要上讲台了。

其实主要是介绍下我们这两年正在开发的网络游戏引擎服务器部分的设计。这里有 PPT 可以下载

November 25, 2007

随机数有多随机?

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

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

最近几天,有测试人员向我抱怨,我们游戏中某些概率设定总感觉有点怪怪的。似乎跟文档上的不同。

这种抱怨并不少见,许多网络游戏玩家都在抱怨系统生成的随机数不太对劲。善良点的玩家会归咎到自己的 RP 上,阴谋论者则指责系统作弊。运营着的游戏背后,数值策划和程序员们有苦说不出。

有必要科普一些数学常识,也作为我周末读书的一些笔记。

November 15, 2007

思维的惯性

晚上在办公室晃荡,对面的同事在加班写代码。我凑上去看看在写什么。我向他了解了后明白了,大约是服务器上角色 buff 的实现吧。

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

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

这里不谈游戏设定,谈谈实现。

October 07, 2007

网络游戏的技术基础

晚上已经回到办公室,飞机下降的时候天气不好,颠簸的很厉害,居然有点晕机的感觉。可能是这几天身体不是好的缘故吧。下了飞机大雨,直接打车到楼下的 KFC 吃垃圾食品,然后就坐到了熟悉的椅子上。

真还别说,环境不同,心境就不同。一坐上办公桌前的椅子上,就有做事情的感觉。沾着家里的椅子就是放松休息了。

刚才发现了透明的一篇文章:从游戏看货币,大约是对我前段时间写的一篇东西的评论。

正好这两天在家没事也在想这个问题,想着想着就不由自主多写几句了。

July 19, 2007

模型顶点数据的压缩

缘起:听天下组的同事谈起,游戏的资源数据量太大,导致了加载时间过长,影响到了操作感。最终不得不对数据进行压缩。

当玩家配置的物理内存足够大时,往往资源数据压缩会适得其反。因为多出来的数据解压缩的过程会占用掉太多的 CPU 时间。物理内存够大的话,操作系统会尽量的拿出物理内存做磁盘 IO 的 cache ,即使你的程序不占用太多的逻辑内存,而反复从硬盘加载大块数据,也不会感觉到磁盘速度的影响。当数据量大一个一个临界时,被迫做不断的外存内存的数据交换,这个时候,数据压缩就会体现出优势。因为解压缩的 CPU 时间消耗是远远小于硬盘 IO 所消耗的时间的。

btw, 玩现在的 MMORPG 往往配置更大的物理内存得到的性能提升,比升级 CPU 或显卡要划算的多,就是源于这个道理。通常 MMORPG 都需要配置海量的资源数据,来应付玩家的个性化需求。

天下组的同事暂时只做了骨骼动作信息的压缩。这个这里暂且不谈,我想写写关于模型顶点数据的压缩。记录下这两天在思考的一个有损压缩算法。

July 13, 2007

游戏中的货币

曾经写过一篇关于网络游戏中的货币经济系统的文章,由于我本人对经济学只是浅尝,读书不多,所知甚为有限,怕是贻笑大方了。但这不影响我对此继续抱有极大的兴趣。最近,又再思索那个困扰游戏设计者的问题:究竟如何用游戏规则来稳定虚拟货币。

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

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

虚拟货币的多重职能,使得在架构虚拟社会的规则时,需要万般小心。而虚拟货币也往往因其多重职能,使得游戏中的市场调节能力减弱。现存的几乎所有网游中都没有设计出一个央行的角色,还真怪不得通货膨胀得不到有效的控制了。

那么,能否构建出一个更接近现实社会的经济模型呢?对于设计一个较之现存游戏更有趣好玩的经济系统,即使这不是唯一之道,但至少是一条值得尝试的路。今天在这里记录一些尚未深思熟虑的想法,权作自己的笔记。方家读过,请一笑了之。

July 06, 2007

唯一的游戏世界

今天写下上一篇 blog 之后,跟另一个组的同事讨论了我的这篇文章。他们的项目先是多服务器的架构,后来重构后改成了单服务器的设计。我们的讨论第一个出现的分歧就是在于对多服务器设计的复杂度会造成的影响。

讨论了一段时间后发现大家的对一些问题的定义从一开始就有区别。回头来大家换个角度讨论了一下,发现其实那些分歧都是不存在的。

讨论告一段落后,我浏览了一遍聊天记录,觉得有必要总结一下 :)

三年前,我跟公司一些策划同事有接连几天的争执:到底玩家是否需要一个宏大的虚拟世界?或是我们若实现这样一个虚拟世界,到底有没有价值?该怎样维护这样的一个大世界,让它不会受到一些暂时性设计 bug 的毁坏性影响?

可以说,三年前的争论是导致我成立独立团队做现在这样一个项目的重要起因之一。因为当时,我几乎得不到任何的支持,策划,程序,美术方面等等几乎都是不赞成的意见。

那个时候,我也的确找不到确凿的证据来说服大家。但今天,思路清晰了许多。

July 05, 2007

游戏服务器组间的通讯

网络游戏世界的构建有越来越大的趋势,游戏设计者希望更多的人可以发生互动。技术人员的工作就是满足这些越来越 BT 的需求。

我们目前这个项目由于是自己主导设计,而我本人又是技术方案的设计者。所以,技术解决不了的问题就不能乱发牢骚了。作为游戏设计者,我希望整个游戏世界的参于者可以在一个唯一的大世界中生存,他们永远有发生互动的可能。注意这里只是保留这种可能性,实际上,即使是现实社会,每个人的社交圈子都不大。即使是千军万马的战场上,无论是将军还是士兵,都不需要直接跟太多人互动。

我们的游戏的技术解决方案仍旧是将游戏大世界分成若干独立服务器组,人为的将人群切分成更小的独立单位。这里,技术上需要解决的是:服务器组间可以灵活的交换数据。

June 21, 2007

平台无关的游戏引擎

一直以来,我们的新引擎一直以跨平台为设计目标。这倒不是说,我们有多重视非 Windows 平台的用户。只是我觉得,一个好的设计一定是很容易做到平台无关的。对于做跨平台开发这件事情,公司里支持的人寥寥。光老丁都几次三番劝我不要把精力花在无谓的地方。

唉,怎么说呢。写了这么多年程序,我一直把编写代码和设计软件作为一件很有趣的事情在做。所以我并不认为我做的一切是一种工作,它是我的玩具。早就不需要担心后半辈子的生活问题,所以没有人可以阻止我做想做的事情,更何况我认为良好的设计造就优秀的产品。今天看似多花的精力,日后慢慢的会给出回报。

回想当年做西游的客户端,我固执的把内存的占用量控制在 64M 左右,让低配置的机器也可以流畅的运行。为了达到这一点,当年多花了好多的精力。做内存中的精灵压缩,做地图的动态加载,做图象数据的 cache 和主动交换,改动许多我认为会更多占用内存的数据结构,阻止美术的一切可能过于消耗内存的设计。

这些在我离开西游的开发后的这么多年里,配合硬件的发展,往日做的那些,得以让后来的不断扩展玩法和美术资源可以稳定的进行。后期的开发维护人员可以用足够的东西来“浪费”。前期的种种约束和正是为了后期的无拘束扩展,直到这些项目顺利的走完生命期。

我希望几年之后,依旧有人感谢我当下做过的努力。

June 08, 2007

2007 年玩家主流显卡配置

本文版权归所有、谢绝任何形式的(部分或全部内容)转载

花了两天和同事一起做了一次数据挖掘工作。

前几天拿到了大量的显卡标识串统计数据(百万条级别),开始做数据分析。因为数据不太规则,所以颇花了些工夫。我想数据的来源和分析结果未得到公司允许前,都不能公开。不过我想在这里透露一些大略信息,对从事游戏开发的朋友(尤其是商业 3d 游戏)会有不小的帮助。

目前,NVidia 、ATI 、Intel 三家几乎垄断了玩家的显卡市场,市场份额超过了 95% 。如果你硬要考虑一些小厂商的话,不妨关注一下 VIA(包括其收购的 S3)和 SiS 。算上这两家已经涵盖了 99% 以上的玩家机器了。

一些若干年前风光过的显卡,如 Voodoo Trident 等现在依然有人用,但如今已经非常稀少。当然,还有人用一些更为稀少的专业显卡,或是我没听过的品牌的垃圾卡(疑是电子垃圾)在玩游戏 :D

May 24, 2007

DXT 图片压缩

这两天在写 DDS 格式的解码程序。DDS 是微软为 DirectX 开发的一种图片格式,MSDN 上可以查到其文件格式说明:DDS File Reference

其中的 DXT 图片压缩格式,现在已经为绝大多数 3D 显卡硬件所支持。(它使用了由 S3 公司所发明的一种有损图象压缩算法。btw, 在我的那本书中,P232 有所提及)。DXT 格式 也叫作 S3TC ,现在可以被流行看图软件直接显示的图象格式中,只有 .dds 文件支持这种压缩。为了开发方便,我们的引擎也就支持了 .dds 文件的加载。

一起做引擎的同事希望即使在硬件不支持的时候,我们也能正常加载并使用贴图,所以便有了对 DXT 软解码的需求。

好在以前研究过一些,写起来也不麻烦。

May 11, 2007

资源的内存管理及多线程预读

网络游戏的 client 开发中,很重要的一块就是资源管理。游戏引擎的好坏在此高下立现。这方面我做过许多研究和一些尝试。近年写的 blog 中,已有两篇关于这个话题的:基于垃圾回收的资源管理动态加载资源

最近在重构引擎,再次考虑这一个模块的设计时,又有了一些不算新的想法。今天写了一天程序,一半时间在考虑接口的设计,头文件改了又改。最终决定把想到的东西在这里写出来,算是对自己思考过程的一个梳理。

March 30, 2007

游戏服务器内的组播

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

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

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

March 29, 2007

游戏服务器处理多个连接入口的方案

最近在考虑为一组游戏服务器配置多个连接入口。这个需求来至于我们的国情。作为大的游戏运营商,势必要考虑国内的网络状况——南北不通的现状。以往别的公司的代理游戏,由于不是自己开发,都选择了一个实际的方案:在北网通和南电信各放若干组服务器。北边来的在北边玩,南方住的安居在南方。

我们的游戏却不行,因为我需要一个完整的大世界,必须解决南北互通的问题。据我所知国内运营的游戏 EVE 是比较好解决了这个问题的。

我们自己的游戏大多也解决了,只是宣传上还是鼓励玩家登陆相应的服务器。我们的解决方案本质上很简单。建立有多个出口的机房,同时拥有电信和网通的线路。或是用自己的线路互联电信和网通的机器。这后者普通用户自己在家也可以做,只要你肯花钱,同时购买电信的 ADSL 于网通的宽带即可。目前许多城市两者都向大众提供服务。

当然,最终我们还是需要编写服务器的程序员做一些配合。

March 20, 2007

为何麻将如此流行?

曾经有种流行的说法是,中国人喜欢打麻将,日本人喜爱围棋,而美国人多打桥牌。这类文章 google 一搜一大把。

当然中国人或是韩国人也喜欢下围棋,而日本人也没以前那么爱围棋了。八十年代的时候,似乎在国内校园里也非常流行打桥牌。而桥牌在美国现在还是不是那么那么流行,就不得而知了。所谓国民的特性从所喜爱的游戏中可看出总总之观点,我一直是不置可否的。今天写的跟这些无关。

由于家庭渊源,我个人不喜欢打麻将。但对麻将也没有感情上的厌恶。小时候即没见父母打过,也不曾见过传送中的因为麻将而导致的家破人亡、妻离子散。只觉得麻将无非一种有竞技性质的桌上游戏而已。

我对麻将所知非常有限,规则陆陆续续的了解了许多。大约知道各地的细则不太一样,大体却是相差不大。似乎体育总局定过一个国标麻将 ,我们的 popo 游戏 就是按这个做的,据我所知,喜欢玩这个规则的不多。大家还是按地域各打各的一套。这也是边锋游戏成功的秘诀之一。

那么,在我看来的一个普通游戏,甚至没有统一明确的规则,为何风靡整个华人世界呢?

February 12, 2007

我们需要 photoshop 之外的选择

游戏的美术工作有时是挺枯燥乏味的。我在公司这几年看到太多美术,连续几天的辛勤工作,只为了将一批图按同样的模式修改成另一个样子。甚至这个工作只是修修通道、转转图片格式等等。

由于有些工作流程比较繁琐,甚至可能会有些变化,并不是每次操作的人都愿意使用 photoshop 中带的批量处理模式来提高效率。最终造成了一种奇怪的现象:明明人手充足,每个人每天都在重负荷的工作,但是整体的完成度却提不上去。在许多时间里,大家干的并不是创造性的工作,而是一些并不需要多少脑力的活儿。

今天碰到件事,我们需要给一些人物角色图片勾一下边。也就是把动画图素展开成带 alpha 通道的图片序列。然后把通道部分提取出来,轮廓扩大、羽化、上色,再叠加回原来的图。这样做的目的是可以把游戏里的角色从背景中突显出来。

February 01, 2007

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

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

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

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

January 15, 2007

3D engine ,中间层的缺失

我们的游戏引擎已经开发了一年半了,其中 3d 引擎部分也做了近一年。

一个好的引擎,渲染部分总是容易做的。因为面对的问题比较单一,资料也很丰富。需要克服的问题很有针对性,即使短期解决不了的问题,放在那里也关系不大。我们团队有两个同事拥有完整 3d engine 开发经验,所以在渲染引擎接口设计部分也不会走太大弯路。(不过事实上,因为基础构件的重写,渲染引擎也是几经修改的)

最近 3d engine 部分又面临一次大的重构。起因是这样的:

December 29, 2006

碰撞检测

我始终认为,在 MMORPG 里采用多边形碰撞检测是件很傻的事情。当然傻不是坏事,基于多边形碰撞检测,一帧检查一次的这种做法,实现起来非常简单。很符合 kiss 原则。我们只需要一点点数学知识和一点点编程技能就能做出来了。反正 client 上,也就检查一个主角。加上可以使用简化的碰撞模型,进一步的减少运算量。

但是放在服务器上,这个运算量可不小。所以这几天我寻思着找个更好的方法出来。

December 06, 2006

在 Windows 下使用 Timer 驱动游戏

在 Windows 平台下写游戏,相比 console 等其它平台,最麻烦之事莫过于让游戏窗口于其它窗口良好的相处。

即使是全屏模式,其实也还是一个窗口。如果你不去跑窗口的消息循环,一个劲的刷新屏幕,我估计要被所有 Windows 用户骂死。

那么怎样让你的游戏程序做一个 Windows 下的良好公民呢?

October 29, 2006

用四叉树管理散布在平面上的对象

周末一直在考虑怎样在游戏服务器中保存和管理那些有平面坐标的对象。希望能方便的查到每个对象附近的东西。以往用过的方法是给(平面)场景打上格子,然后再把每个对象放入相应的格子中。

这次又遇到这个问题,却不想用网格的方法来解决问题了。

原因主要是这么几点:一,用网格对于大场景特别消耗内存,而且不太适合做无限延展的场景。二,查询每个对象周围的东西时,不太方便。格子的粒度越小,速度越慢。

虽然这两个问题,都可以通过改进算法来回避。不过这次,我想尝试一下用四叉树解决这个问题。

October 19, 2006

数据服务器的设计

今天开始正式开始做数据服务器。在这点上,我希望一组服务器上所有的逻辑服务遇到的数据存取需求都通过一个单一的数据服务器完成。而且,写入数据是单向通讯的。即,逻辑服务器只提读写盘请求,而无须确认。写数据好说,读数据稍微难处理一点,我现在的方案是,数据服务器加载数据的部分只对位置服务器负责,把数据提交到位置服务器即可。位置服务器可以通过分析数据知道玩家的数据流应该流向哪台逻辑服务器。

以上逻辑是基于每个玩家有独立的数据的,而且一个玩家同时只存在于唯一一个场景。也就是说,当一组数据存活的时候,只唯一属于一台逻辑服务器。这样做的好处是,切换场景非常的简单,只是让玩家从一个场景退出,给数据服务器发出写盘指令,并发送所有数据。数据服务器写盘的同时也 cache 了这些数据,并向位置服务器提交新的位置,并把这些数据转发向位置服务器。位置服务器可以再转交给新的场景。

对于玩家登陆和登出的处理并没有特别之处,我们可以设立两个虚拟场景,一个负责登入,一个负责登出。每个新连接自动导入登入场景,这个场景负责发出加载指令(下面可以看到,甚至无须设置加载数据的协议)。然后再做一个自动的场景切换操作即可。而玩家登出,则是转入登出场景,这是一个黑洞,玩家的连接可以在这里安全的断掉。

当玩家不停的穿梭于各个场景之间时,为了避免频繁的数据转发,我们可以给玩家数据做一个赃标记。如果没有弄赃,实际的数据可以不被转发。这个标记的另一个意义在于,若数据没有弄赃,而数据服务器的 cache 中又没有数据时,就需要从外存加载了。其实这就是一个读请求。

月初我在公司内部讲解这个设计时,遭到了一些同事的疑问。最典型的一个是,帮派信息如何处理。的确,类似帮派的信息,不属于任何一个玩家。如果你单独设一个非玩家对象保存这些数据时,可能会分布到不同的逻辑服务器上。的确对数据服务器的设计是一个挑战。

今天仔细考虑过以后,我发现可以从设计上避免这个问题。方法如下:

October 18, 2006

多进程的游戏服务器设计

目前,我们的游戏服务器组是按多进程的方式设计的。强调多进程,是想提另外一点,我们每个进程上是单线程的。所以,我们在设计中,系统的复杂点在于进程间如何交换数据;而不需要考虑线程间的数据锁问题。

如果肆意的做进程间通讯,在进程数量不断增加后,会使系统混乱不可控。经过分析后,我决定做如下的限制:

  1. 如果一个进程需要和多个服务器做双向通讯,那么这个进程不能处理复杂的逻辑,而只是过滤和转发数据用。即,这样的一个进程 S ,只会把进程 A 发过来的数据转发到 B ;或把进程 B 发过来的数据转发到 A 。或者从一端发过来的数据,经过简单的协议分析后,可以分发到不同的地方。例如,把客户端发过来的数据包中的聊天信息分离处理,交到聊天进程处理。

  2. 有逻辑处理的进程上的数据流一定是单向的,它可以从多个数据源读取数据,但是处理后一定反馈到另外的地方,而不需要和数据源做逻辑上的交互。

  3. 每个进程尽可能的保持单个输入点,或是单个输出点。

  4. 所有费时的操作均发到独立的进程,以队列方式处理。

  5. 按功能和场景划分进程,单一服务和单一场景中不再分离出多个进程做负载均衡。

性能问题上,我是这样考虑的:

我们应该充分利用多核的优势,这会是日后的发展方向。让每个进程要么处理大流量小计算量的工作;要么处理小流量大计算量的工作。这样多个进程放在一台物理机器上可以更加充分的利用机器的资源。

单线程多进程的设计,个人认为更能发挥多核的优势。这是因为没有了锁,每个线程都可以以最大吞吐量工作。增加的负担只是进程间的数据复制,在网游这种复杂逻辑的系统中,一般不会比逻辑计算更早成为瓶颈。如果担心,单线程没有利用多核计算的优势,不妨考虑以下的例子:

计算 a/b+c/d+e/f ,如果我们在一个进程中开三条线程利用三个核同时计算 a/b c/d e/f 固然不错,但它增加了程序设计的复杂度。而换个思路,做成三个进程,第一个只算 a/b 把结果交给第二个进程去算 c/d 于之的和,再交个第三个进程算 e/f 。对于单次运算来算,虽然成本增加了。它需要做额外的进程间通讯复制中间结果。但,如果我们有大量连续的这样的计算要做,整体的吞吐量却增加了。因为在算某次的 a/b 的时候,前一次的 c/d 可能在另一个核中并行计算着。

具体的设计中,我们只需要把处理数据包的任务切细,适当增加处理流水线的长度,就可以提高整个系统的吞吐量了。由于逻辑操作是单线程的,所以另需要注意的一点是,所有费时的操作都应该转发到独立的进程中异步完成。比如下面会提到的数据存取服务。

对于具体的场景管理是这样做的:

October 02, 2006

服务器消息的广播

MMO 的 engine 中,需要解决的最重要的问题之一,就是如何把游戏世界中的状态改变消息正确的通知给需要知道这条信息的玩家。

通常,我们会设定每个玩家的 AOI ( Area Of Interest )。当一个对象发生改变时,它会把消息广播出去;那些 AOI 覆盖到它的玩家会收到这些广播消息。

但是,在我们现在的游戏系统中,简单的 AOI 系统是不够用的。比如,类似 wow 中的盗贼隐身,明明已经离你很近,但是你的 client 却看不见他。诚然,我们可以在 client 判断这个逻辑,对盗贼不于显示,而 engine 依然广播盗贼移动的消息。对于不作弊的 client ,这是个简单的解决方案。但在理论上却提供了看见隐身人的可能性,所以,我期望有更好的方法让 engine 可以只将消息广播到那些必须接收这些消息的 client 。但是,在实现这个同时,又不能让底层 engine 牵扯太多逻辑信息。

这里提出一个简单的方案: