趣味Python游戏编程:第2章 用鼠标控制游戏:拼图

趣味Python游戏编程:第2章 用鼠标控制游戏:拼图

在第1章中,我们完成了一个弹跳小球的游戏。虽然实现了小球图像的移动和显示,但是准确来说,它还不能算作一个游戏。因为游戏是用来“玩”的,也就是说,玩家需要通过某种方式来操作游戏的角色,而在弹跳小球游戏中,小球只是自己在不停地移动,它的运动并没有受到我们的控制。若想编写一款真正的游戏,则要考虑为游戏添加控制操作。

在本章中,我们将一起编写一个拼图游戏,即将一些零散的图片块拼合成一幅完整的图像。我们希望通过鼠标来操作图片块,具体来说,当玩家用鼠标单击图片块时可以移动它的位置,当所有的图片块都移动到正确位置时游戏便完成了。让我们一起来编写这个游戏吧!

本章主要涉及如下知识点:

自动创建多个不同角色

使用随机函数

处理鼠标单击事件

模块化编程方法

播放声音文件

在窗口显示文字

2.1 添加图片块

2.1.1 准备图片资源

由于拼图游戏是将一系列小的图片块拼成一幅完整的大图像,因此首先需为游戏准备一些小图片,要保证每一张小图片都是完整图像的某个组成部分。在拼图游戏中,图片块越多,操作的难度就越大。为了简单起见,这里只使用了9张图片来完成拼图,如图2.1所示。

在这里插入图片描述

2.1.2 创建游戏场景

作为游戏程序编写的第一步,需要创建一个游戏角色活动的场景。首先确定场景的大小。我们的游戏使用9个图片块来完成拼图,最终图像的尺寸应该是3×3个图片块大小,即水平方向3个图片块,垂直方向也是3个图片块。每个图片块的宽度和高度都是96像素,因此最终图像的宽度和高度则都是96的3倍,以此作为游戏场景的宽度和高度值,代码如下所示:

SIZE = 96
WIDTH = SIZE * 3
HEIGHT = SIZE * 3

上述代码首先定义了一个常量SIZE,用来表示图片块的尺寸。然后将场景的宽度WIDTH和高度HEIGHT分别设置为SIZE的3倍。

接着显示场景,这就需要在draw()函数中进行处理。为程序加入如下代码:

def draw():
    screen.fill((255, 255, 255))

可以看到,这里仍然采用最简单的办法,即使用单一的颜色来填充整个游戏场景。这里使用白色作为背景颜色。

2.1.3 用列表管理图片块

游戏场景已经准备好了,接下来要考虑创建游戏角色。对于拼图游戏来说,游戏角色就是玩家需要操纵的图片块,准确来说,每一个图片块都对应着一个游戏角色。在弹跳小球游戏中,我们学习了如何创建游戏角色,以及如何对多个游戏角色统一管理,现在是时候将之前学到的知识运用一下了!

还记得吗?可以通过Actor()构造方法来创建一个角色,只需要将角色的图片文件名作为参数传递给Actor()方法即可。例如创建第一个图片块角色的代码可以这样写:

pic = Actor("puzzle_pic0" )

为了管理9个图片块,需要定义一个列表,将创建的图片块角色统统加入其中。代码如下所示:

pics = [ ]
pics.append(pic)

上述代码中首先定义了一个图片块列表pics,然后调用append()方法将刚才创建的图片块角色pic加入列表。

那么问题来了,总共有9张图片,难道要一张一张地创建角色并加入列表吗?当然不用亲自动手,重复的操作交给循环语句来处理就好了。由于知道循环的确切次数,可以使用计数循环来完成创建角色的操作,在这里循环的次数为8次。

慢着,是不是弄错了,一共9张图片,难道循环次数不是9次吗?没错,只有8次。根据游戏规则,需要移动图片块的位置,倘若将全部的9张图片都加入游戏场景,那么图片块就没移动的空间了,因此需要预留一个空白的区域用来移动图片块。

原来如此。那么还有一个问题就是,每个图片文件的名字都不一样,怎么在循环语句中通过不同的文件名来创建相应的图片块角色呢?这个问题不难解决。请仔细看看图2.1中展示的图片文件名,你会发现所有文件名的前面都是一串相同的字符“puzzle_pic”,只是后面接了个不同的数字(按照从0到8的顺序依次编号)。其实这样来命名就是为了便于循环操作的。

我们可以将图片文件的名字分为两部分,前面是字符串“puzzle_pic”,后面是数字,而数字的编号恰好可以和循环变量的值对应起来。于是可以编写如下代码来自动创建所有图片块角色:
for i in range(8):
pic = Actor(“puzzle_pic” + str(i))
pic.index = i
pics.append(pic)

需要注意的是,由于循环变量i的类型是整型,而图片文件名的类型是字符型,为了将i的值转化为图片文件名中的字符,首先需要调用Python内置的str()函数进行类型转换,然后通过字符串连接操作符“+”将文件名的前后两部分连接起来,从而形成完整的图片文件名。

接着将完整的图片文件名传入Actor()方法,便可创建相应的图片块角色。角色创建之后随即将其加入图片块列表。

此外,上述代码还为每个图片块角色定义了一个属性index,并将循环变量的值赋予该属性。那么这个属性有什么作用呢?它实际上记录了图片块的编号,具体作用后面再进行解释。

2.2 打乱图片块

下面要考虑将图片块显示在窗口中。若要将所有的图片块显示在窗口中,则需要依次从列表中读取各图片块并显示。需要注意的是,目前我们是按照图片文件名从puzzle_pic0到puzzle_pic7的次序将图片块加入列表中的,很显然,图片块在列表中的位置也是固定的。这就意味着每次运行游戏的时候,图片块会按照固定次序显示在窗口中。这显然不符合游戏的规则。

在拼图游戏中,玩家需要将分散的图片块拼合成完整的图像。所谓分散的图片块,就是说各个图片块在窗口中的位置不是事先确定的,而是随机变化的。因此在每次的游戏中,图片块的位置都是不相同的。这也是拼图游戏的乐趣所在,每次游戏都是新的挑战,玩家可以反复进行游戏。

那么怎样让图片块在窗口中分散地显示出来呢?上面提到,所有图片块都是按固定次序保存在列表中的,只要设法随机打乱图片块在列表中的次序,然后再将它们显示出来,则可以达到分散显示的效果。这需要借助Python提供的随机函数。

2.2.1 使用随机函数

在程序设计中经常会遇到使用随机数的情况,对于游戏程序更是如此。为了增添游戏的乐趣或挑战,游戏往往会通过随机发生的事件来制造惊喜或障碍,而这都需要借助随机数来实现。

说明:

为了让编程者方便地获取随机数,Python中提供了一个名叫random的库,其中包含了很多对随机数进行处理的函数。我们希望随机打乱图片块在列表中的次序,因此可以使用random库中的shuffle()函数。只需要将列表所为参数传入该函数,它可以随机地改变各个元素在列表中的位置。

需要注意的是,使用shuffle()函数前首先得导入random库,因此在程序的最前面加上这一行代码:

import random

接着在之前编写的程序后面加入如下语句:

random.shuffle(pics)

该语句表示调用random库的shuffle()函数,参数为图片块列表pics。执行这句之后,pics中各个图片块的次序便被随机打乱了。

2.2.2 将图片块显示出来

最后显示图片块。既然列表已经被随机打乱次序,只需要从列表中依次取出各个图片块并显示即可。然而还有一个问题。就是目前还没有为图片块设置坐标。在创建图片块的时候,在Actor()方法中仅仅传入了图片文件名,而没有传入坐标值。在这种情况下,Pgzero会自动地将每个图片块的坐标设置为(0,0),如果直接显示,可以看到所有图片块都会“挤”在窗口的左上角。

为了让图片能够显示在正确的位置,需要为每个图片块设置坐标。当然,你可以逐个设置8张图片,但既然循环语句可以自动操作,我们又何必浪费时间亲手去做呢?实际上,可以使用计数循环语句,从列表中依次取出每个图片块并为其设置坐标即可。

那么各个图片块的坐标又分别设为多少呢?由于我们的拼图是由9张图片块组成的3×3的网格,因此程序窗口也可以相应地划分为9个方格,一个方格中显示一个图片块。每个方格的位置可以用一对数值(i,j)来表示,其中i代表方格所在列的编号,而j表示方格所在行的编号。各图片块所在方格的位置编号如图2.2所示(注意行和列的编号都是从0开始的)。

这样一来,每个图片块的坐标便可以通过其所在的方格编号来确定,只需要将图片块的大小乘上相应的列号或行号即可。于是可以编写如下代码为所有图片块设置坐标:

for i in range(8):
    pics[i].left = i % 3 * SIZE
    pics[i].top = i // 3 * SIZE

在这里插入图片描述

在循环运行过程中,循环变量i的值从0增加到7,i的每个取值都对应着列表pics中的一个图片块pics[i],同时该图片块的坐标也可通过i求得。由于拼图中总共有3列图片块,因此可用i对3进行“取余”运算,得到pics[i]所在方格的列号,而用i对3进行“取整”运算来得到行号。接着分别将列号和行号乘上图片块的尺寸SIZE,便可算出pics[i]的左边界和上边界的位置,并分别赋值给pics[i]的left和top属性。

最后修改draw()函数,在其中加入遍历循环语句,依次调用每个图片块的draw()方法进行显示。修改后的draw()函数代码如下所示:

def draw():
    screen.fill((255, 255, 255
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值