为了避免读者产生误会,先声明两点:第一,我们不是专业的游戏开发商,我们没有完整的游戏策划、编剧、美术、动画、测试等开发团队,我们只是想通过游戏开发这种实战的方式来给Python学习者带来感官上的体验,加深对Python基础知识的掌握。所以,如果你想成为一名专业的游戏开发工程师,这里的文章可能满足不了你的要求;第二,标题上的(面向过程)用意是给还没有学到面向对象相关知识的初学者做参考,而不是说这个游戏一定要用面向过程的方式来实现。我们后续还会用面向对象的方式再写一遍,届时读者就可以看出这两种实现方式的区别了。目前有一点是明确的,那就是游戏开发肯定是使用面向对象的方式更为合适的。
下面先附上游戏演示的视频,让读者知道本教案的最终成果是怎么样的,再来给读者逐步分解设计和开发的思路。游戏演示视频如下:
本教案不仅仅包含了Python编程基础知识的应用,还包含了软件开发项目的一般开发流程在里面。这绝对是网上少有的免费教学文案,我们也是仅此一次,后续的实战课程也不可能再像本教案这样从头到尾的带领大家做项目了。因此,建议初学者可以跟着我们教案的思路从头到尾做一遍,包括从需求分析、系统设计、模块设计、模块编码到集成测试、直至游戏能成功运行的整个过程。完成后,你会对 入门篇 中所学到的Python知识有更深刻的理解,学以致用的感觉也会大大地提升你的学习动力哦。
推箱子游戏是一款经典的益智类游戏,之所以选它作为我们Python游戏开发实战的第一例:一方面是因为它已经有几十年的历史了,游戏逻辑简单明了,且游戏受众范围非常之广,从小孩到老人都可以玩,笔者最早是在黑白屏的诺基亚手机上开始接触这款游戏的,至今已接近20年了,虽然演化出很多的版本,但基本规则都是一样的;另一方面是因为它的游戏界面是一个匀称的二维矩阵,能用Python的元组或者列表来简单的表示游戏元素,且游戏元素不多,适合没什么UI设计经验的Python开发者上手,不需要花太多的精力去设计UI也能弄出效果不错的游戏界面,笔者也是UI设计的小白哦。
对于任何一个软件项目来说,弄清楚软件需求是项目开发的第一步,如果需求不明确将会导致无法进行系统设计,而没有稳定的系统架构,在软件编码的过程中代码迭代将会非常频繁,甚至导致项目最终无法落地,即使项目最终能够落地也只会是个缺陷集中营,后期将浪费大量的人力财力去做维护!因此,我们首要任务是弄清楚游戏的需求以及运行规则。
一般来说我们需要先收集软件功能需求,然后再分解为软件设计需求。功能需求一般是产品经理负责,用于说清楚产品的功能、性能等用户级要求;而设计需求是在满足功能需求的基础上,一般由项目经理或者系统工程师负责,将功能需求分解或转换为研发可实现的开发要求。
|
由于推箱子游戏的需求太简单,我们就不作茧自缚了。流程是为研发服务的而不是成为研发的束缚,本项目直接统称为软件需求就O了。
推箱子的游戏规则或需求如下:
-
游戏采用关卡制,只有通过上一级关卡才能进入它的下一级关卡,直至游戏通关。
-
游戏中的每个关卡的地图都必须由墙壁围成一个闭环的圈,且墙壁不可移动、不可进入。
-
一个关卡内可以有1个或多个箱子和1个或多个目标,但箱子数量和目标数量必须一致,且一个目标只能进去一个箱子,箱子与目标没有绑定关系,可随便搭配。
-
每个游戏关卡中都有且只有一个游戏角色,如图中的蟒蛇,它是用户直接控制的对象。
-
允许游戏地图中存在一个或者多个障碍物,障碍物不可移动、不可进入,相当于墙壁。
-
用户通过键盘上的上、下、左、右方向键来控制角色进行水平或垂直移动,每按一次按键只能移动一步,但不允许斜向移动。
-
目标本身不能移动,但目标位置可以被角色或者箱子进入,箱子进入目标时变成绿色图标以提示用户,角色进入目标则没有提示,但可以根据移动方向改变角色的左右朝向。
-
角色或者箱子可以从目标位置里面移动出来,角色从目标移动出来后需要还原为目标图标(大绿点)。初始状态时,允许箱子在目标里但不允许角色站在目标里。
-
当角色移动方向的前方是箱子时,移动角色会把箱子往前推,即角色和箱子同时往前移动一步,但角色只能往前推动箱子不能往后拉动箱子,而且只有箱子的前方是空地或者目标位置才允许往前移动,也就是说角色不允许同时推动两个或以上的箱子。
-
当角色碰到墙壁或者障碍物时虽然不允许进入,但可以改变角色的左右朝向。
-
把所有箱子推进目标位置即视为为当前游戏关卡胜利,给出提示并进入下一关。
-
支持在游戏地图上方显示当前关卡及移动步数统计信息,例如:
![]() |
这里罗列的需求大多数只是游戏的规则,读者日后如果从事真正的项目开发,项目需求肯定是比这里详细很多的。例如,要说清楚游戏界面的大小、结构、颜色甚至需要说清楚游戏中提示信息的位置、字体以及内容等,这里篇幅有限,就不搞那么详细了,但为了严谨,笔者还是要说明一下,免得以后你们怪我错误引导。笔者曾在华为工作8年多,当过多年的系统工程师和项目经理,所以请相信,我很清楚应该把什么样子的需求传递给研发,才能更有效的落地。
正如我们在 第1课 Python简介 中描述的一样,用Python去开发一个电子邮件客户端,你不需要从底层的网络协议栈开始开发,只需要使用现成的SMTP库再搭配上UI开发工具就能轻松完成。对于Python游戏开发也一样,目前有很多的第三方Python游戏开发库,例如pygame、PyOgre、Blender等。
其中pygame是专门用来制作2D游戏的开源库,它提供了图像处理、声音播放、事件处理、碰撞检测等功能,可以快速的制作包含动画、音效以及交互性等在内的各种游戏元素。我们可以使用pygame封装好的接口就能轻松地实现2D游戏开发。当然,我们也不能完全当小白,拿来主义的前提还是需要简单的先了解一下它的接口使用方法和大体设计框架的。
对于pygame,这里先简单介绍一下如何安装和导入,然后再简单讲解一下它的工作原理和使用要求,以便于读者能够很好的理解我们接下来的界面元素设计及基本框架设计思路。安装和导入pygame的方法与安装和导入其他第三方库方法是一样的,如下:
安装方法(使用阿里云镜像):
pip install pygame -i https://mirrors.aliyun.com/pypi/simple/
导入方法:
import pygame
简单的说,pygame就是通过创建一个窗口,然后在窗口中绘制图形、导入图片、写入文本等并控制他们的运动或行为的方式来实现游戏的。pygame支持通过监控事件的方法来捕获用户的输入,以达到游戏与玩家进行互动的目的,且pygame内置了一些音效和声音播放功能,可以增强游戏的娱乐性,我们这里暂时没有用到它声音播放相关的功能。
对于推箱子游戏,我们前面已经讲过,它的游戏界面很简单,打开任意一个关卡地图都可以看出,它其实就是7个相同大小的游戏元素(墙壁、障碍物、角色、箱子、空地、目标)的矩阵排列,例如下面关卡地图:
本关卡地图是一个7行6列的元素矩阵 |
我们只需要把这些元素切割成一个个图标(建议用png格式),然后通过pygame把他们绘制到窗口中就可以实现游戏界面的显示了。切割后的8个图标如下(由于游戏角色有左右两个朝向,所以多出1个图标):
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
pygame使用blit函数在窗口上绘制图形:
screen.blit(surface, dest, area=None, special_flags=0)
第一个参数surface就是图像源,第二个参数dest是一个元组,表示绘制的起始坐标(单位为像素),(0, 0)表示窗口的左上角,往下和往右数字递增(不能使用负数的坐标!),例如(200, 300)表示在水平方向200像素、垂直方向300像素处的位置。后两个参数暂时先不管。
由于pygame绘制游戏元素的起始位置是一个坐标,坐标又是以像素作为单位的,我们的图片不可能是1个像素这么小,因此我们必须给每个元素分配一定的像素空间,我们称之为block,并把元素图片设置成与block相同的大小。例如,我们分配50\*50像素作为一个block的大小,这样的话,只要元素的图片大小也是50\*50像素,元素就可以刚好占满一个block,元素与元素之间就可以无缝对接了,如下:
当然,把游戏元素设计成大小均一并不是所有的游戏都是如此要求,你完全可以设计不一样大小的元素,只是管理起来稍微复杂一点而已。然后,只要给每个元素分配一个唯一的编码,在Python代码中就可以使用这个编码来替代各种元素进行管理了。本项目设计的游戏元素和实际地图显示的关系如下:
< |