逻辑服务器的设计:
逻辑服务器的设计思路其实很简单,我们把游戏里的对象分为2大类,城市和人。所有的游戏逻辑操作都是围绕这这两个对象进行的。其中城市对象又还可以细分为多个子对象,这些对象在结构上是属于城市的,它们分别是码头、船厂、交易所、银行、酒馆。
在游戏进行的时候,玩家要进行某些操作的时候(购买货物)会向服务器端发送游戏消息,这时候,服务器在收到消息后,会通过消息玩家的ID知道玩家当前在那个城市里,然后再由这个城市对象去处理这条游戏消息。在城市对象收到游戏消息后,首先是对一级分类进行判断,这个级别的分类标准是逻辑上的分类,这点在前面已经说过了。这时候如果消息的逻辑分类是交易所,城市对象,会再调用城市对象里面的交易所对象去执行该条游戏消息,这时候,城市对象就要根据消息的二级分类来判断玩家到底是要做什么事情了。这时候,如果消息是BuyReq 者说明玩家是打算购买一类货物,交易所对象,再从消息里附带的结构体变量读出要购买货物的编号和数量。这时候交易所首先要判断,这类货物在本交易所里时候存在,并且能够卖,如果可以,再调用用户对象的购买货物函数,由用户对象进行下一步的处理(看看时候有足够的钱,玩家的船是否还能装得下这个货物等等..)如果可以,则由用户类返回成功,否则,返回错误的信息。在交易所收到用户类返回的信息后,再根据返回的结果,生成相应的游戏消息发还给用户。
整个过程很简单,所以,在项目开始的时候,我就先那这个系统开刀,在分配项目任务的时候,我也就有限考虑自己做简单的东西,然后把复杂的地图服务器仍给了另外一位同学^_^。不过虽然这个模块简单,不过涉及到的东西很多,难度虽然不大,但是很烦琐,一个小小的问题就可能造成今后游戏存在的严重bug,所以在进行没有逻辑事件的处理都是时候,我都是很小心的在做,刚开始的时候,还写过一定的测试用例去测试系统,不过现在看来,当时写的测试用例存在有一定的问题:
1。是在完成代码后才写测试,XP方法要求测试用例要优先与代码的编写。
2。只写了测试过程,没有编写自动化的结果判断。有测试,就必须要有预期的测试结果,当时写的测试用例大多只是看看那个函数能够正确运行而已,所有结果都是直接输出到屏幕上,让我自己来判断,在测试用例写过一段时间后,要测试的部分太多,有些看不过来了,所以写了测试输入,一定要想好输出结果,并且要让测试代码自己把函数返回结果与想好的输出对结果进行判断,从而减少人工判断的错误性。
3。测试用例过少,因为时间的关系,只是在前面的阶段写过一定的测试用例,到后来进度紧张后,就没空去进行测试了。归结起来,应该是没有一个良好的测试框架与测试机制,有好的框架,可以减少测试用例的编写时间,从而有更多的时间去编写代码。同时因为项目不是什么正规的项目,所以对测试的要求也不是太严格。
除了测试存在不足外,程序的整个结构上也存在着严重的不足:
1。当初因为考虑得简单,每个玩家的游戏消息都会有一个与它相对应的游戏消息,所以,我在程序里大胆的采用了函数返回游戏消息指针的方式,在系统完成游戏消息处理后,产生一条游戏消息,并且把改游戏消息以返回消息内存首地址指针的方式返回给调用处理的函数。这样一层层的返回,一直返回到socket的OnRead()函数,然后再在这个函数里send数据给客户端。这样的设计在刚开始的时候,并没有觉得什么不托,但是实际到后期才发觉,这样的设计有一个很大的不方便,有些从客户端来的游戏消息,它的返回消息可能不只一个,所以在一个函数的返回值里就不太好处理了。这个问题我开始的时候没有太注意,因为很多消息都只是有一条返回消息而已,哪知到后来系统的扩展,很多函数处理都要返回多条数据,所以,在后来的不得不在逻辑处理里面增加消息发送函数。不过这样给我的感觉就不是很舒服了,逻辑处理里面就不应该存在其它的东西,现在增加的消息的发送,就不是很好了。不过一直到现在,我都没有找到合适的结局方法,所以,如果在一开始的时候先想好消息该怎么发送,就不会存在这样的混乱了。
2。在前面的代码里,遗漏有创建游戏消息的代码(交易所),后来感觉不爽,因为要创建的东西很多,而且很多都是重复的,所以就用一个模版来处理创建过程。再到了后来,觉得逻辑代码里存在很多游戏逻辑消息的变量赋值过程,这样的代码也不是很好看,所以有进一步把这个东西独立出来做个函数,这样逻辑处理代码就好看很多了。这个过程是一个不断的发展过程,也都是看到不足后才进行处理,所以,如果当初就和上面的游戏数据发送一起考虑好,就不会留下很多垃圾代码(这些代码我现在还没有处理掉)。
地图服务器的设计:
对于地图服务器的设计,在网上关于它的文章一直都比较多,说得最多的就是如何实现让客户端与服务器进行同步。所以,在项目开始的时候,这个部分能够参考的文章很多,不过也因为这个系统是交给一个完全没有做过游戏的同学来制作,所以很多时候,很多概念性的东西需要理解,在理解的时候会造成一定的偏差,所以系统在实现的时候不是很完善。不过也因为进行开发的这位同学的实力不同一般,所以地图服务器还是能够运行的,只不过^_^
当初设计的时候,考虑到游戏里存在着2种移动场景,一个是海上,一个是城市。城市的特点是有边界,海上地图的特点是超大无缝地图,所以在设计的时候,我们有限考虑的是海上场景的地图设计。城市地图可以看做是海上地图的一个特例,地图的四周只有少量或者根本没有相关的连接地图。
超大地图的设计是采取对地图进行分块处理,把整个海洋世界分解为多块小地图,每块地图的大小和一个游戏屏幕(800×600)的大小差不多。服务器里存放有所有地图的信息,当一位玩家参数移动的时候,会把自己的移动请求信息发送到相关的9块地图上(自己所在的地图,以及以自己为中心邻接的8张地图),这样每个客户端都能接收到来自自己周围9张地图上其他玩家的移动信息,从而实现了系统的互动。
概念上说起来是很简单,但是到实践的时候要考虑的地方就很多了,例如移动方向,阻挡,最麻烦的就是地图切换了,需要通知相关地图的玩家进入以及相关地图上的玩家退出等游戏事件,而且还存在则跨越地图后的移动处理等问题。总之因为我只是提供方案者,具体编码不是我来做,所以我对里面的具体细节了解得不是很详细,只能大概的理一下他的思路。
服务器还是基于面向对象的设计思路来做的,整个系统里分了3个对象,玩家、地图、地图管理。玩家对象和我上面的概念一样,是存储玩家信息,并存在着一定的于地图相关的处理函数。地图对象存放的是一小张地图的信息,和与当张地图操作相关的操作。地图管理可以看做是超大地图类,它的作用就是管理无数个地图对象,让它们在逻辑上拼接成为一张超大的地图。
同时除了这3个对象外,还存在着一个状态机的过程。我们对这个状态机的理解很简单,就是每隔一定的周期计算一次玩家的新位置,让他们看起来是在连续不断的运动。这个东西不是很难理解,但是处理起来确看起来有些让人困扰,首先是服务器端的在虚拟机执行时间中断的时间间隔与客户端的不同,设计的时候,服务器端是每隔0.5s执行一次,而客户端如果也按照服务器端的设计出处理,明显会让玩家感觉地图上的人物一卡一卡的在进行跳跃运动,所以客户端在虚拟机的时间间隔势必要比服务器短很多,我们的设计是0.1S执行一次。这样的短的间隔就会造成客户端的移动数据与服务器端的移动数据不一致。解决这个不同步的问题采用了多种方案,其中包括定期发送玩家的位置的同步信息。不过也因为时间关系,这个同步方案没有完全的实现,所以系统还是存在着不同步的现象。
不过地图服务器里的注解还是比较详细的,所以这里要说明的不是很多,理解它架构就好理解了。理解架构后再看一下“地图服务器工作日志.doc”会对这个开发过程有一定的了解。
posted on 2009-02-12 02:38
小王 阅读(550)
评论(0) 编辑 收藏 引用