2005年7月7日星期四

网络游戏的一点开发经验

以前从没接触过网络游戏方面的编写。前段时间因为课程原因,和班里同学组队写了一个网络游戏,虽然功能上比较简陋,但是麻雀虽小,五脏俱全,网络游戏应该有的几个基本元素都有了,也算是在网络编程上的一次新的尝试了吧。

游戏是用 Java 写的,原因是,我们学那本教材的示例是用 Java 写的。从产生最初的设想,到最后的完成总共是一个半月左右。因为是组队编写,所以在分工合作上就必须十分注意,而且一个月内要完成一个具有界面、网络通讯、游戏逻辑等等内容的软件对于一个没有经验的人来说工作量太大了些。

我们采用的方法是分工-整合,即先通过分析把软件分割成几个技术块,分给组员去研究,等他们把自己那块研究得很透彻了以后,就把自己在那一块的经验、需要注意的地方、一个自己写的典型的示例交给一个整合者。整合者需要较高的程序开发能力,至少要对各个技术块都要有一点了解,并且能够很快从各研究者那里学到东西,然后把各个部分整合起来,完成整个软件。

实际当中,我们分割的技术块有以下几个:

1. 核心算法、逻辑(同时也是整合者);

2. 界面设计;

3. AWT + Swing;

4. 网络通讯(组播 + 流式 Socket)

5. 安装和分发。

非常有幸的,我担任核心算法的那一块,从自己,也从别人那里学到了很多。

在编写过程中主要遇到了以下几个问题:

1. 各个客户端如何互相识别;

2. 非原子对象如何通过网络传输;

3. 组播的可靠性;

4. 逻辑部分的架构怎么设计,才能保证简洁、有效、少出错。

相应的每个问题的最后解决方案是:

1. 我们考虑了是否使用服务器作为中间人。一种情况就是各个客户端就通过组播传递一个只属于自己的 ID。但是因为组播机制的问题,我们(好像)不能仅仅经由组播组得知组里有多少成员,更不可能收到类似“有新的成员加入组”的消息。经过考虑,我们还是决定使用客户端-服务器模型,有服务器分发 ID,这样,服务器就能分担很多原本在客户端的开销了(特别是使用多线程以后)。

2. 很明显的,用序列化。为了这个,我和一个同学争论了一个晚上,他想用类似网页表单的形式,最后终于说服了他(有现成的技术干嘛不用)。

3. 通过最后的测试,我发现,组播的时序是一个很麻烦的问题,特别是在还有网络延迟的情况。在游戏中,3 个客户端在接收(并发送),1 个客户端在发送(并接收),我怎么保证客户端 A 他先收到客户端 B 接收后发送的消息,还是客户端 C 直接发送的消息?如何保证自己发送的消息自己能最快地接收到?实际情况中,几种可能性都是存在的,也都发生过。我没有找到什么很好的解决办法,只能是增加条件判断。

4. 架构,最难办的东西。就这么一个小游戏,要把它的规则用程序描述出来也是不容易的。更难的是在怎样有效、正确的传递结果,特别是在上面提到的不太可靠的环境下。为了赶时间,我没有花很多时间在设计架构上,还是采用了沿时间的线性编程。事实证明,这简直就是地狱,你将需要非常多的 if, else 放在各个关键点,很多时候为了解决一个匪夷所思的 Bug,又要添加 AND 或者 OR。到最后,逻辑部分变得很冗繁,很复杂,即使有 Bug 也很难找到。这也算是对我偷懒的惩罚吧。

其实对于架构,也想到一种方法,时间表。事前为每一个客户端制作一份时间表,时间表中记录了客户端每一步应该做的事情,这样每个客户端就不需要关心其他客户端发生的步骤,只需要将其他客户端发送的数据接收并正确显示即可。制作和使用时间表并不容易,但是对于复杂流程来说,这会是一个比较好的解决方案,从逻辑上来说,这就是把整个过程式的流程分割了并分发给每个客户端。每个客户端的对应时间表是在一份基本时间表加上以客户端的本地的独特数据(如 ID)作为基础的变化后生成的。我想在以后哪次写类似的软件时有可能会用到这种技术。

另外,以前都是用 C++,C# 的,第一次用 Java,感觉 .NET 确实是从 Java 中汲取了很多好的思想、细节,摒弃了很多麻烦、不实用的东西。两者在语法结构上都很相似,但感觉 C# 更像 C++ 一些。(而正是这许多些微的不同,形成了很多各式各样的争论。)个人来说并不觉得 Java 就比 .NET 差或者落后,只是比较不习惯。还是要看在什么领域里面应用,有些适合 J ,有些时候 N,没有一定的。不过,对于 Java 的图形界面设计,我是深恶痛绝。要想用 AWT 设计出像 .NET 一样整洁清新的“一般”窗体是多么困难的事啊!

还有很多感想,一下子也想不出。以后再说吧。

没有评论: