最近无意中看到http://blog.jobbole.com/46308/ (中文翻译版本) 这是一个pygame“教学”游戏,自己也想试试看游戏的制作,于是边学边做。本游戏暂时取名ZSgame,ZS即Zealseeker的缩写。

游戏的制作基本就是仿照原文章中的方式,连资源都是用它的。贵在学习嘛。唯一的不同是,原游戏的写法是个纯面向过程的写法,比较好理解,但是扩展性会比较差,不适合做长久的打算。

下面介绍一下pygame做游戏的几个步骤,其实无论用什么做游戏,这几个步骤显然是不可避免的。介绍前先简单介绍下我设计的游戏。本来想做一个“塔防”类游戏,即操作者在地图上安防防御塔,一段时间内会有规律出现怪物,怪物会走向一个地方,防御塔一定要在他们走到前毁灭他们。植物大战僵尸就是一个比较经典的塔防类游戏。当然为了简变,我的游戏中怪物、防御塔只有一种,走路方式也比较“傻”,就是往前走,不做任何其他。

游戏的源码放在 https://github.com/zealseeker/zsgame 另提供windows可执行文件下载 。

1# 编程前期准备

既然是用pygame来做游戏,那么显然需要python以及pygame包,这个在上述的博客中已经很详细的介绍了,这里不多讲。

2# 游戏内对象的设计。

所有游戏中出现的东西,都可以理解为对象,那LOL为例,比如里面的英雄,小兵野怪,防御塔水晶显然是,然后所有的物品,包括插的眼。这些都是游戏的对象,那么描述对象的代码,便是编程中的“类”。
在本游戏中,主要考虑这几个类:防御塔(defence)、怪物(badguy)、防御塔射出的箭(arrow)。正因为资源都是用《兔子和獾》的游戏,所以里面的变量名字也学习它的,比如badguy等。
在我的设计里,箭是由防御塔射出的,所以每个防御塔里都有个arrows变量用于储存所有它射出的箭。而防御塔和怪物则是属于整个游戏的,即全局变量。防御塔要做的事情就是定期(频率由攻速决定)“寻找对象”,如果找到则向他发动攻击,射出箭。当然,由于箭是储存在防御塔里的,所以还得写一个函数用以控制箭的移动,这样主程序遍历所有的防御塔,由防御塔来控制箭的移动就行了。
箭这个对象有两个功能,一个是移动,随着时间的推移,箭的位置在变。还有个功能就是判断箭是否已经射到怪物上面,如果射到则返回True。防御塔调用它如果返回是True的话,则可以删掉这个箭,并且让它所发动的那个怪物掉血。
至于怪物,就一个功能,移动。。。。当然在我的程序里加了个getRect函数,用于得到怪物的正方形,主要调用者就是箭,它要判断是否射到了怪物。

3# 主程序循环

源代码的主程序写的比较乱,虽然读起来可理解,毕竟面向过程,但如果要改则可能无从下手。我写代码依然没能脱离这种感觉,好在大多数事件都写进了类,所以代码的量比较少,可仍然不知道如何让逻辑更清晰一点,我的设计如下:

1. 防御塔先控制箭矢让他们移动,并画出他们的模样(defence.controlArrow);防御塔画出自己(defence.draw)。
2. 怪物移动并检查是否移出了地图(badguy.moveOut);检查怪物是否已经被射死了(health<=0);画出剩余的怪物。这里有个小细节,原先我用的是两个if判断,后来发现如果同时出现,那么怪物会被移除两次,就报错。解决的方法是现在这样的if..elif结构,也就说如果离开的同时被射死了,依然算没有来得及消灭。
3. 在界面上显示金币数量,剩余可逃过怪物数量,剩余出现数量。用途请看第五步。
4. 定期增加怪物数量,定期让防御塔寻找怪物(虽然说理论上由防御塔类决定,不过介于编程简单,直接写在主程序里,让他们20次循环攻击一次,理论上1秒循环60帧,也就是1秒钟攻击三次,当然由于显卡、CPU不同,有些电脑就会比较慢。
当然在真正写程序的时候需要写一些代码,比如建立变量Badtime用于记录循环的次数,循环最开始要让屏幕清空,循环的最后面要输出画的东西(pygame.display.flip)。

4# 事件

每次循环除了要执行上述内容外,还需要检查“事件”是否发生了,事件包括鼠标、键盘的操作或者也可以自定义。在本游戏中,主要监控鼠标的点击事件MOUSEBUTTONDOWN,这里buttondown不考虑是哪个键,当然今后如果左右键有区别则得考虑的,具体还得参考pygame的document。鼠标点击后则做一些判断,在我的游戏中,先判断是否有50块,没就啥事都没有。如果有50块则看如果在鼠标点击位置如果放一个新的防御塔是否会和已有的防御塔冲突,如果冲突,则升级原防御塔。(其实理论上这样不大好,最好的情况应该直接判断鼠标是否在原防御塔上面;我这样设计是为了偷懒,因为这样就能保证两个防御塔不会叠在一起)。
除了游戏性质的事件,还有其他的事件,比如下面要说的游戏被关闭的事件,pygame也为我们想好了。

5# 游戏结束判断

这个理论上在游戏设计最开始就得想好了,不过在程序设计的时候可以放在最后。在这里游戏结束的判断就特别简单了,正如第三部分提到的,有两个值决定的,一个是剩余可逃过怪物数量,如果这个数量到达0,则游戏立刻结束。还有个变量是剩余怪物,如果没有了,游戏也结束。不过有个细节,由于剩余怪物时出一个减1,最后到0的时候则不再出,可游戏还没结束,一直到最后一个死掉或者离开地图后才结束。做法是监视badguys列表的宽度,当他最后为0时则游戏结束。
当然,游戏结束还有另一种可能,那就是中途被用户终止了。尽管游戏设计里面并没有任何按钮开关可以终止游戏,不过玩家还是可以关掉的嘛。这些操作判定都可以由“事件”来完成,玩家关掉窗口会触发pygame.QUIT事件,那么我们就要在这里把我们的程序也关掉啦(sys.exit)

pygame1.png
pygame2.png

这里要说一下,这只是一种最简单的游戏设计及编程实现,还未提到过任何优化的过程。很显然我的游戏里每次循环都清空屏幕又重构屏幕这样是很浪费资源的,而且图片都是直接载入。关于如何优化的部分,感觉这篇文章还是很不错的,可供大家学习。
http://www.360doc.com/content/13/0125/13/3046928_262312058.shtml