网络游戏综合编程(下)

技术与开发

从上期开始,我们将之前的知识串起来完成了一个简单的网络游戏,希望通过实战练习,让大家能巩固以前学到的知识,加深对网游开发的认识。上期我们完成了MMORPG游戏的单机部分——创建游戏地图和控制游戏角色在游戏场景里走动。但一个人走实在是太无聊了,这一期我们将实现多个玩家联网在同一个游戏场景里走动。所谓独乐乐不如众乐乐,是吧?

一、制作简单的游戏服务器程序

要让多个游戏客户端连接起来,需要一个游戏服务器程序。我们的游戏服务器程序的主要作用是:某个玩家角色在行走时,通知他附近的所有玩家这一动作。注意,这里只是通知他附近的玩家,而不是游戏场景里的所有玩家。一个游戏场景可以是很大的,里面也许有成千上万个玩家,如果每一个都进行通知将要很大的工作量,要很多时间,而且没有必要,相离很远的玩家是“看”不见他走动的,所以只要通知他附近的玩家便行了。

24-f12-1.jpg

网络拓扑结构我们采用简单的C/S结构,如图1所示。C是指客户端(Client),S是指服务器端(Server),多台客户端连到一台服务器端上。

简单的做法如下:假如有两个玩家A与B在同一个游戏场景里,并且走得很近。当A行走的时候执行“行走”这个动作,并发送“行走”这个消息给游戏服务器。游戏服务器收到这个消息后,找出玩家A附近的玩家——即玩家B。游戏服务器发送“玩家A行走”这个消息给玩家B,玩家B收到这个消息后执行“玩家A行走”这个动作。这便是玩家在游戏场景里走动所要执行的步骤。

下面是游戏客户端执行玩家行走的伪代码:

Walk( xPos, yPos ); // 行走

WalkMsg msg;

Msg.x = xPos;

Msg.y = yPos;

NotifyServer( MSGID_WALK, msg ); // 通知服务器

下面是游戏服务器处理玩家行走的伪代码:

void PlayWalk( const DWORD PlayerID, const int xPos, const int yPos )

{ PLAYER_VECTOR vecPlayers;

FindNearbyPlayers( PlayerID, vecPlayers ); // 找出附近的玩家

WalkMsg msg;

msg.PlayerID = PlayerID;

msg.x = xPos;

msg.y = yPos;

NotifyClient( MSGID_WALK, msg, vecPlayers ); 通知附近的玩家 }

编写游戏服务器不同于编写游戏客户端,游戏服务器要求更高的稳定性。游戏服务器要求连续运行很长时间,如果程序出错,那么连接在该服务器上的所有玩家都会被断开连接,这是很糟糕的事,也是游戏运营商最头痛的事之一。而另一方面,游戏服务器对网络性能要求也很高,要求能支持多个游戏客户端的连接。如果是使用WinSock做网络开发的话,一般会选择性能最佳的完成端口模型。对完成商品模型有兴趣的读者可以找有关资料进行学习,推荐《Windows网络编程(第二版)》。

二、编写游戏脚本

24-f12-2.jpg

图2是游戏中角色对话的场景:

还记得你玩过的RPG游戏里那有趣而感人的剧情吗?还记得游戏中那经典的对白吗?这些都是游戏的剧本所设定好的,这里所指的游戏剧本就好像电影剧本一样,它主导着整个游戏,是RPG游戏的灵魂。

那在游戏中如何表现剧情呢?在程序中直接添加对白吗?可以,但方法太笨了。像现在RPG游戏的庞大剧情要用这种方法来实现工作量大得惊人,当要改某段剧情的时候就要修改一大堆代码,容易发生错误。所以大家就选择了一个聪明的方法——给游戏写剧本。

这里的游戏剧本就是脚本。游戏剧本不是直接用我们的语言写出来,而是用我们自定义的脚本语言。例如:

TALK("阿勇" , "妖怪!我勇士阿勇奉女王之命来搞定你们,准备受死吧!");

TALK("妖怪A" , "嘻嘻!就凭你?");

TALK("阿勇" , "哼!等会看你还笑不笑得出!");

FIGHT("妖怪A");

RETURN();

以上就是一段自定义的游戏脚本,TALK是一个谈话命令,FIGHT是一个战斗命令。以上描述的就是阿勇与妖怪A的谈话,然后就开始打斗了。这就是一个简单的脚本,怎么样?是不是有点像电影剧本?更方便的是这些脚本可以用Windows的记事本程序来编写。

虽然游戏脚本就好像电影剧本,但写起来却不是那样自由。也必须像我们编程一样,要按一定的格式来编写。好在我们可以做自己冒险之旅的导演,设定脚本语言的格式。就以上面的游戏脚本为例,每一句的脚本格式如下:

命令(参数1,参数2,……,参数N);

这看起来更像是一个函数的调用。每一句脚本由命令、括号、参数等组成,最后以一个分号来结束一句脚本。为了统一,脚本中的命令一律采用大写字母。括号中的参数以逗号分隔开,像TALK命令那样的参数要用双引号括起来,用双引号括起来的字符串一律用全角格式编写。每一段脚本最后以“RETURN();”结束,就好像函数那样。

游戏脚本在游戏开发当中起着非常重要的作用。它具有很强的灵活性,游戏策划人员可以把脚本文件当作是剧本。游戏中许多内容不必写死在程序当中,试想像《魔兽世界》这样一个大型的网络游戏,如果什么东西都写死在游戏程序中,日后程序的细微变动都要进行编译,一个大项目的编译所用的时间是相当长的。

值得高兴的是我们不必像上面那样自己去编写脚本语言。目前有许多脚本语言可供我们选择。这里选择比较流行的Python与Lua进行介绍。

* Python

Python是一种简单易学,功能强大的编程语言,它有高效率的高层数据结构,简单而有效地实现面向对象编程。Python简洁的语法和对动态输入的支持,再加上解释性语言的本质,使得它在大多数平台上的许多领域都是一个理想的脚本语言,特别适用于快速的应用程序开发。

Python语言是面向对象的,而且它和C++结合工作得很好,所以得到了许多C++程序员的青睐。

Python语言是开源的,可以上www.python.org下载最新版本。

* Lua

Lua是一个扩展式程序设计语言,它被设计成支持通用的过程式编程,并有相关数据描述的设施。Lua也能对面向对象编程、函数式编程、数据驱动式编程提供很好的支持。它可以作为一个强大、轻量的脚本语言,供任何需要的程序使用。

跟Python语言一样,Lua语言也是开源的,可以上www.lua.org下载最新版本。

三、网游开发学无止境

网络游戏开发是一项很大的科目,我们一般不可能做到面面俱到。就好像计算机这个大科目一样,有人做美术设计,有人做网页设计,有人做软件开发等。网络游戏开发简单地可以分为图形引擎开发,游戏逻辑开发,游戏服务器开发等。

如果你希望做图形引擎开发,这是一个很大的挑战。目前国内的图形引擎并不成熟,特别是3D图形引擎。你要去学习线性代数、计算机图形学、Direct3D、OpenGL(现在越来越多的游戏都同时支持Direct3D与OpenGL)等等。对游戏逻辑开发有兴趣的,首先你要有扎实的数据结构与算法基础,有较强的逻辑思维能力。对游戏服务器开发有兴趣的,需要深入理解计算网络与各种网络协议。

做网络游戏开发,“钱途”当然很重要。但更重要的是对游戏的浓厚兴趣,对游戏的激情,那样才能全心全意地投入进去,才能开发出好的游戏作品。最好玩的游戏跟最赚钱的游戏,一方面是相辅相成的,另一方面又是矛盾的。

编后:

至此,“走近网游开发”系列文章就全部刊载完毕了。看过本系列文章的朋友会发现,网游开发涉及的知识领域很广,譬如我们系列中讲解过的C++语言、数据结构与算法、Windows程序开发、DirectX、网络通讯编程等,因此一个人要想全部精通几乎是不可能的!我的建议是,大家应该根据自己的兴趣,同时结合发展前景来选择网游开发中的某一个领域,然后深入学习。