现在你已经掌握了 Scratch,我们将告诉你如何用 Python 进行基于文本的编码。
吉多·范罗苏姆(Guido van Rossum )以喜剧团 Monty Python 的名字命名的 Python 语言,已经从1991年首次向公众发布的一个业余项目发展成为一种备受喜爱的编程语言,为各种项目提供动力。与 Scratch 的图形化编程不同,Python 是基于文本的:你使用一种简化的语言和特定的格式编写指令,然后由计算机执行。
对于那些已经使用过 Scratch 的人来说,Python 是一个很好的进阶,它提供了更大的灵活性和一个更“传统”的编程环境。不过,这并不是说它很难学:只要稍加练习,任何人都可以编写 Python 程序,从简单的计算到令人惊讶的复杂游戏。
本章建立在《第四章 用 Scratch 3 编程》中介绍的术语和概念之上。如果你还没有完成那一章的练习,可以先回去做完,你将会发现这一章更容易理解了。
介绍 Thonny Python IDE
- A 工具栏:Thonny 的“简单模式”界面使用一个友好的图标栏作为它的菜单,允许你创建、保存、加载和运行你的 Python 程序,以及以各种方式进行测试。
- B 脚本区:脚本区是编写你的 Python 程序的地方,它被分成一个主要的程序区和一个显示行号的小边框。
- C Shell 区:Python Shell 允许你输入单独的指令,一旦你按下回车键,这些指令就会被运行,同时还提供关于运行程序的信息。
Thonny 的版本
Thonny 有两个界面版本。“常规模式”,和一个更适合初学者的“简单模式”。本章使用简单模式,当你从树莓菜单的编程栏打开 Thonny 时,默认会加载该模式。
你的第一个Python程序。Hello, World!
像树莓派上的其他预装程序一样,Thonny 可以从菜单中获得:点击顶部的树莓图标,将光标移到编程(Programming)部分,然后点击 Thonny Python IDE。几秒钟后,Thonny 的用户界面(默认为简单模式)就会加载。
Thonny 是一个被称为集成开发环境(IDE)的软件包,这个听起来很复杂的名字有一个简单的解释:它把你编写或开发软件所需的所有不同的工具聚集在一起,或者说集成在一个用户界面或环境中。现在有很多IDE,其中一些支持许多不同的编程语言,而另一些,如 Thonny,则专注于支持一种语言。
与 Scratch 不同的是,Python 是一种更传统的编程语言,所有代码都需要通过输入编写。点击 Thonny 窗口底部的 Python Shell 区,开始编写你的第一个程序,在按下回车键之前输入以下指令:
print("Hello, World!")
当你按下回车键时,你会看到程序立即开始运行。Python 将在当前 shell 区域内给出回应,显示“Hello, World!” ,如下图所示。这是因为 shell 是通往 Python 解释器的一条捷径,解释器的工作是查看你的指令并解释它们的含义。这就是所谓的交互式模式,你可以把它想成是与人面对面的交谈:你一说完,对方就会立刻给出回应,然后等待你接下来说的话。
Python 在 shell 区域打印“Hello, World!”信息。
语法错误 SYNTAX ERROR
如果你的程序没有运行,而是在 shell 区域打印了一个“SyntaxError”(语法错误)信息,那么在你写的东西中,一定是有一个地方出了错,如下图所示。Python 需要它的指令以一种非常特殊的方式书写:少了一个括号或引号,拼错了“print”或给它一个大写的 P,或者在指令的某个地方添加了额外的符号,它都不会运行。再试着输入指令,在按下回车之前,确保它与上面提供的代码严格一致。
不过你不一定要在交互式模式(Shell 区)下使用 Python。点击 Thonny 窗口中间的脚本区,然后再次输入你的程序。
print("Hello, World!")
当你这次按下回车键时,什么也没有发生——除了你在脚本区得到一个新的空白行。为了使这个版本的程序正常运行,你必须点击Thonny工具条上的“Run”图标。当你点击后,会被要求先保存你的程序;输入一个描述性的名字,如“Hello World”,然后点击确定按钮。一旦你的程序保存完毕,你会看到在 Python Shell 区域出现两条信息,如下图所示。
>>> %Run 'Hello World.py'。
Hello, World!
运行你的简单程序。
其中第一行是 Thonny 的指令,告诉 Python 解释器运行你刚刚保存的程序。第二行是程序的输出——你告诉 Python 要打印的信息。祝贺你:你现在已经在交互式和脚本模式下编写并运行了你的第一个 Python 程序。
挑战:新的消息
你能改变 Python 程序作为其输出打印的信息吗?如果你想增加更多的信息,你会使用交互式模式还是脚本模式?如果你从程序中去掉括号或引号,然后再尝试运行它,会发生什么?
树莓派如何安装中文输入法 scim
如果你希望能让程序中使用中文,就需要安装一个中文输入法。
在树莓派的系统桌面点击顶部的终端图标,打开 LX 终端,然后输入以下指令:
sudo apt-get install scim-pinyin
如下图所示:
回车后,如下图所示,会提示是否需要下载选择:[Y/n],输入y后继续,如下图所示。
安装完毕后,重启树莓派,就能在右上角的状态栏看到多了一个小键盘图标。
现在你可以在编程中,按 “Ctrl+空格键”输入中文了,如下图所示:
接下来的步骤:循环和代码缩进
就像 Scratch 使用类似拼图的堆栈来控制程序的哪些块与其他哪些块相连一样,Python 也有自己的方式来控制其程序运行的顺序——缩进。通过点击 Thonny 工具栏中的“New”图标创建一个新的程序。你不会失去你现有的程序;相反,Thornny 将在脚本区上方创建一个新的标签。开始输入以下内容:
print("循环开始!")
for i in range(10):
第一行会向 Shell 打印一个简单的信息,就像你的 Hello World 程序。第二行开始了一个“定循环(definite loop)”,其工作方式与 Scratch 相同:一个计数器 i 被分配给循环,并通过 range (范围)指令,让 i 从 0 到不超过 10 来计数。尾部的冒号告诉 Python,下一条指令应该是循环的一部分。在 Scratch 中,要包含在循环中的指令会被 C 形块包含。Python 使用了一种不同的方法:缩进代码。下一行会以四个空格开始,当你在输入完第 2 行程序后按下回车键时,Thonny 应该已经添加了这些空格,然后继续输入下面的代码:
print("循环次数:", i)
与其他行相比,空白处将这一行向内推进。这种缩进是 Python 区分循环外指令和循环内指令的方式;缩进的代码被称为嵌套。
你会注意到,当你在第三行结束时按下回车键,Thonny 自动缩进了下一行,假设它是循环的一部分。要消除这一点,只需在输入第四行之前按一次 Backspace 键(也称退格键),然后输入下面的代码:
print("循环结束!")
你的四行程序现在已经完成。第一行位于循环外,只运行一次;第二行设置了循环;第三行位于循环内,每循环一次就运行一次;第四行再次位于循环外。
print("循环开始!")
for i in range(10):
print("循环次数:", i)
print("循环结束!")
点击“Run”图标,将程序保存为“Indentation”(首行缩进),并查看其在 Shell 区的输出如下图所示:
执行一个循环。
从零开始计数
Python 是一种零索引语言——意味着它从 0 开始计数,而不是从 1 开始,这就是为什么你的程序打印的是 0 到 9 的数字,而不是 1 到 10。如果你愿意,你可以通过将 range(10) 指令换成 range(1, 11) ,或者任何你喜欢的其他数字来改变这种设定。
缩进是 Python 的一个强大的部分,也是程序不能按你的预期工作的最常见原因之一。当寻找程序中的问题时,也就是所谓的调试过程,一定要仔细检查缩进情况——尤其是当你开始在循环中嵌套循环时。
Python 也支持无限循环(infinite loop),它的运行没有尽头。要把你的程序从一个确定的循环变成一个无限的循环,请把第2行编辑成:
while True:
如果你现在点击运行图标,你会得到一个错误:NameError: name 'i' is not defined
(名称“i”未被定义)。这是因为你删除了创建变量 i 并为其赋值的那一行。要解决这个问题,只需编辑第3行,使其不再使用该变量。
print("循环运行中!")
点击“Run”图标,如果你动作快的话你会看到“循环开始!”信息,后面是一串永无止境的“循环运行中!”的信息,如下图所示。“循环结束!”信息你永远也没有机会见到,因为循环没有结束条件:每当 Python 打印完“循环运行中!”信息后,它就回到循环的起点,再次打印它……
一个无限循环一直持续到你停止程序为止。
点击 Thonny 工具栏上的“Stop”图标 ,告诉程序停止它正在做的事情,这被称为中断程序。你会看到 Python 的 Shell 区域出现一条信息,程序会直接停止,但不会到达第4行代码。
挑战:循环的循环
你能把这个循环再改成一个定循环吗?你能在程序中添加第二个定循环吗?你将如何在一个循环中再添加一个循环,你希望它如何工作?
条件语句和变量
变量,在所有的编程语言中,不仅仅是为了控制循环而存在。点击 Thonny 菜单上的“New”图标开始一个新的程序,然后在脚本区输入以下内容。
userName = input ("你的名字是什么? ")
点击“Run”图标,将你的程序保存为“Name Test(姓名测试)”,看看在 Shell 区会发生什么:你会被要求输入你的名字。在 Shell 区输入你的名字后按回车键。因为这是你的程序中唯一的指令,所以其他的事都不会发生,如下图所示。如果你想对放置在变量中的数据进行实际操作,你需要在程序中再添加几行。
输入函数可以让你要求用户输入一些文字。
为了使你的程序对这个名字做一些有用的事情,可以通过输入以下内容添加一个条件语句:
if userName == "八戒":
print("你是二师兄!")
else:
print("你不是二师兄!")
记住,当 Thonny 看到你的代码需要缩进时,它会自动这样做——但它不知道你的代码何时需要停止缩进,所以你必须自己删除这些空格。
点击“Run”图标,在 Shell 区域输入你的名字。除非你输入的名字正好是“八戒”,否则你会看到“你不是二师兄!”的信息。再次点击“Run”图标,这次输入“八戒”这个名字——确保和程序中写的一模一样,这一次,程序识别出你实际上是二师兄,如下图所示。
你不是应该去救师傅吗?
“==” 符号告诉 Python 做一个直接的比较,看看变量 userName 是否与你程序中的文本——被称为字符串相匹配。如果你在处理数字,还有其他的比较方法可以做。
> 大于号:看它是否大于另一个数字;
< 小于号:看它是否小于另一个数字;
=> 大于等于号:看它是否等于或大于另一个数字;
=< 小于等于号:看它是否等于或小于另一个数字;
!= 不等于:意思是不等于——与 == 完全相反。
这些符号在技术上被称为比较运算符。
使用 = 和 ==
使用变量的关键是学习=和==之间的区别。 记住:=意味着 “使这个变量等于这个值”,而==意味着 “检查这个变量是否等于这个值”。把它们混为一谈,肯定会导致程序无法运行。
比较运算符也可以在循环中使用。删除第2至第5行,然后在其位置上输入以下内容。
while userName != "八戒":
print("你不是二师兄!再试试")
userName = input ("的名字是什么? ")
print("你是二师兄!")
再次“Run”图标。这一次,程序没有退出,而是一直询问你的名字,直到确认你是二师兄,如下图所示。有点像一个非常简单的密码。要退出这个循环,可以输入“八戒”或者点击 Thonny 工具栏上的停止图标。祝贺你:你现在已经知道如何使用条件语句和比较运算符了!
这个程序将一直询问你的名字,直到你说是“八戒”。
挑战:添加更多问题 你能改变程序来问一个以上的问题,将答案储存在多个变量中吗?你能制作一个程序,使用条件和比较运算符来打印用户输入的数字是否高于或低于5,就像你在“第四章 用Scratch编程”中创建的程序一样吗?
项目1:海龟雪花
现在你了解了 Python 的工作原理,是时候开始尝试玩图形了,下面我们将用一个被称为海龟(turtle)的工具创建一个雪花。
在线项目
这个项目也可以在网上的这个链接 rpf.io/turtle-snowflakes 处找到。
海龟(turtle)最初是数字版本的物理机器人,形如其名,它被设计成可以直线移动、转弯、抬起和放下笔,简单地说就是在移动中开始或停止画线。不像其他一些语言,即 Logo 编程语言和它的许多变种,Python 没有内置的海龟工具——但它有一个附加代码库,以赋予它海龟的能力。库是一堆代码,它增加了新的指令来扩展 Python 的能力,并通过导入命令被带入你的程序。点击“New”图标创建一个新的程序,并输入以下内容:
import turtle
当使用包含在库中的指令时,你必须使用库名,然后是英文句点,最后是指令名。每次输入都很烦人,所以你可以指定一个较短的变量名来代替——它可以只是一个字母,但我们认为它可以使用 pat 作为海龟的昵称,这样会比较方便使用,输入以下内容:
pat = turtle.Turtle()
为了测试你的程序,你需要给你的海龟一些任务,比如让海龟走几步,类似下面的代码:
pat.forward(100)
点击“Run”图标,并将你的程序保存为“Turtle Snowflakes”。当程序保存后,会出现一个名为“Python Turtle Graphics”的新窗口,你会看到程序的结果:你的海龟 pat 会向前移动 100 个单位,在屏幕中间向右画出一条直线,如下图所示。
海龟向前移动,画出一条直线。
切换回 Thonny 主窗口——如果它隐藏在 Turtle Graphics 窗口后面,可以点击 Turtle Graphics 窗口上的最小化按钮,或者点击屏幕上方任务栏中的 Thornny 条目,然后点击“Stop”按钮,关闭 Turtle Graphics 窗口。
用手打出每一条运动指令会很乏味,所以我们可以删除第3行并创建一个循环来完成创建形状的艰苦工作。
for i in range(2):
pat.forward(100)
pat.right(60)
pat.forward(100)
pat.right(120)
运行你的程序,帕特将画出一个单一的平行四边形,如下图所示。
通过结合转弯和运动,你可以画出一个菱形。
要把它变成一个雪花状的形状,请点击 Thonny 主窗口中的“Stop”按钮,并在你的循环外围再创建一个循环,添加以下行作为第3行。
for i in range(10):
并在你的程序底部写上以下内容。
pat.right(36)
你的程序不能按原样运行,因为现有的循环没有正确缩进。要解决这个问题,请点击现有循环中每一行的开头(第4行到第8行)然后按四次空格键来纠正缩进。你的程序现在应该看起来像这样:
import turtle
pat = turtle.Turtle()
for i in range(10):
for i in range(2):
pat.forward(100)
pat.right(60)
pat.forward(100)
pat.right(120)
pat.right(36)
点击“Run”图标,观察海龟:它会像以前一样画一个平行四边形,但画完后会转36度再画一个,然后再画一个,以此类推,直到屏幕上有十个重叠的平行四边形——看起来有点像雪花,如下图所示。
利用重复形状,可以做出更复杂的形状。
当机器人海龟在一张大纸上用单一颜色作画时,Python 的模拟海龟可以使用一系列颜色。在第 3 行插入下面两行新代码,把原来第 3 行及以下的代码排在新代码的下面。
turtle.Screen().bgcolor("blue")
pat.color("cyan")
再次运行你的程序,你会看到新代码的效果:Turtle Graphics 窗口的背景颜色变成了蓝色,而雪花现在是青色的(下图)。
改变背景和雪花的颜色。
你也可以使用随机库,从一个列表中随机选择颜色。回到你的程序顶部,在第2行插入以下内容:
import random
将现在第 4 行的背景颜色从“blue”(蓝色)改为“grey”(灰色),然后插入新的第 5 行,创建一个名为“colours”的新变量。
colours = ["cyan", "purple", "white", "blue"]
美式拼写
许多编程语言使用美式英语拼写,Python 也不例外:改变海龟笔颜色的命令被拼写为 color ,如果你用英式英语拼写为 colour,它就不会工作。然而,变量可以有任何你喜欢的拼写方式——这就是为什么你可以将你的新变量命名为 colours,并且让 Python 明白。
这种由方括号标记类型的变量被称为列表。在这个例子中,列表中设置了雪花段的可能颜色——但是你仍然需要告诉 Python 在每次循环重复时选择其中的一种。在程序的最后,输入以下内容,确保它缩进了四个空格,这样它就形成了外循环的一部分,就像它上面的那一行。
pat.color(random.choice(colours))
点击“Run”图标,雪花的菱形将再次被绘制。不过这一次,它绘制每一个花瓣的时候,Python 都将从你的列表中选择一个随机的颜色。现在我们给予雪花一个令人愉快的、多色的结果,如下图所示。
为“花瓣”使用随机颜色。
为了使雪花看起来不那么简陋,而更像一个真正的雪花,添加一个新的第 6 行,直接在你的颜色列表下面,并输入以下内容。
pat.penup()
pat.forward(90)
pat.left(45)
pat.pendown()
如果使用海龟机器人,penup 和 pendown 指令会将物理画笔抬起和放下,但在虚拟世界中只是告诉你的海龟停止和开始画线。不过这一次,你不是使用一个循环,而是要创建一个函数——一个你可以随时调用的代码段,就像创建你自己的 Python 指令。
首先删除绘制平行四边形雪花的代码:即从第10行的pat.color("cyan")
指令到第17行的pat.right(36)
指令之间的一切。保留pat.color(random.choice(colors))
指令,但在该行的开头添加一个哈希符号(#),这可以注释掉一条指令,意味着 Python 将会忽略它。你可以使用注释来给你的代码添加解释,这将使你在几个月后回到这里或把它送给别人时更容易理解
创建你的函数,它将被命名为“branch”(分支),在第10行,pat.pendown()
的下面输入以下指令:
def branch():
如此就定义了你的函数:branch。当你按下回车键时,Thonny 会自动为该函数的指令添加缩进。键入以下内容,密切注意缩进——因为在某些行,你将会把代码缩进三个层次的深度!
for i in range(3):
for i in range(3):
pat.forward(30)
pat.backward(30)
pat.right(45)
pat.left(90)
pat.backward(30)
pat.left(45)
pat.right(90)
pat.forward(90)
最后,在你的程序底部创建一个新的循环——但要在注释过的颜色线之上,以运行或调用你的新函数:
for i in range(8):
branch()
pat.left(45)
最终你的程序如下图所示:
import turtle
import random
pat = turtle.Turtle()
turtle.Screen().bgcolor("grey")
colours = ["cyan", "purple", "white", "blue"]
pat.penup()
pat.forward(90)
pat.left(45)
pat.pendown()
def branch():
for i in range(3):
for i in range(3):
pat.forward(30)
pat.backward(30)
pat.right(45)
pat.left(90)
pat.backward(30)
pat.left(45)
pat.right(90)
pat.forward(90)
for i in range(8):
branch()
pat.left(45)
# pat.color(random.choice(colours))
点击“Run”图标,观察图形窗口中 pat 按照你的指示进行绘制,如下图所示。祝贺你:现在的雪花看起来靠谱多了!
树枝状的分支使它看起来更像一片雪花。
挑战:下一步是什么?
你能用你注释过的指令让雪花的分支以不同的颜色绘制吗?你能创建一个“雪花”函数,并使用它在屏幕上画出许多雪花吗?你能让你的程序随机地改变雪花的大小和颜色吗?
项目2:恐怖找不同游戏
Python 还可以处理图片和声音以及基于海龟的图形,这可以用来对你的朋友进行恶作剧,效果很赞——就让我们做一个伪装的“找不同”游戏,最适合在万圣节拿来给你的朋友们献宝。
在线项目
这个项目也可以在 rpf.io/scary-spot 上进行,也可以在树莓派上通过这个链接下载所需的素材。
这个项目需要两张图片——一张是伪装成“找不同”游戏的图片和一个有点“可怕 ”的惊喜图片,以及一个鬼哭狼嚎的惨叫的音效声音文件。点击树莓图标加载树莓派操作系统菜单,选择“互联网”类别,并点击 Chromium 网络浏览器。当它加载完毕后,在地址栏中输入 rpf.io/spot-pic,然后按回车键。在图片上点击右键,点击“图片另存为…”从左侧的列表中选择保存到“桌面”,然后点击保存。再点击 Chromium 的地址栏,然后输入 rpf.io/scary-pic,接着按回车键。像以前一样,右击图片,点击“图片另存为…”,选择保存到“桌面”,然后点击保存。
spot_the_diff.png
scary_face.png
对于你需要的声音文件,点击回到地址栏,输入 rpf.io/scream,然后按回车键。这个文件,是那个带来惊喜的尖叫声的声音文件,它会被自动播放——但在你使用它之前,需要保存它。在小型音频播放器上点击右键,点击“音频另存为…”,选择主文件夹,然后点击保存。现在你可以关闭 Chromium 窗口。
en_images_scream.wav
点击 Thonny 工具栏上的“New”图标,开始一个新项目。像以前一样,你将使用一个库来扩展 Python 的能力:Pygame 库,正如它的名字所示,它是为游戏而创建的。输入以下内容。
import pygame
你将需要其他库的一些部分,以及 Pygame 库的一个小部分。通过输入以下内容来导入这些东西。
from pygame.locals import *
from time import sleep
from random import randrange
from 指令的工作方式与 import 指令不同,它允许你只导入你需要的库的一部分,而不是整个库。
扩展:关于 Python 库四种导入方式
我们之前导入 Turtle 库的方法是用“import+库名称”来实现的,这是“完全导入法”,另一种导入部分库功能的“部分导入方法”:“from+库名称+import+功能”。
这两种导入法在使用上会有什么区别吗? 首先是导入的指令不同;其次是使用函数的方法不同。我们来拿之前我们学习过的 turtle 库来举例: 我们在编写让海龟前进 100 的代码的时候我们其实是可以一气呵成的,写成右半部分代码的形式。 Python 当中的点其实有分支的含义,表示的是什么工具库里面的什么方法,比如说创建 Turtle 函数是turtle工具库里面的,我们如果要使用 Turtle 就需要用 turtle.Turtle 来告诉电脑从哪找到 Turtle 这个函数。因此,如果我们使用 import turtle 这个语句来完全导入 turtle 库的话,我们使用前进指令或者其他指令的方法就至少需要两个点来找到这个函数的位置。 使用“完全导入法”的时候,我们需要在使用的函数前面,加上我们的工具库名称加上点的形式。 使用“部分导入法”的时候,我们在代码当中使用了什么函数,就得导入什么函数,并且不再需要 turtle 加点的前缀。
第三种导入库的方法:from+库名称+import
这里的 代表的就是全部的意思,如果使用的是这种导入库的方法,我们在代码当中可以完全不使用点了,直接使用函数名称即可。
第四种导入库的方法——导入第三方库的同时,用“as”对库名称进行二次修改: 要注意的是改名之后原名称就不能使用了 。
接下来,你需要对 Pygame 进行设置;这被称为初始化。 Pygame 需要知道玩家的显示器或电视的宽度和高度,也就是它的分辨率。输入以下内容。
pygame.init()
width = pygame.display.Info().current_w
height = pygame.display.Info().current_h
设置 Pygame 的最后一步是创建其窗口,Pygame 称之为屏幕。输入以下内容。
screen = pygame.display.set_mode((width, height))
pygame.quit()
注意中间的留空行;这是要添加你的程序的地方。不过现在,请点击“Run”图标,将你的程序保存为“Spot the Difference”(),然后观看。Pygame 将创建一个窗口,用黑色背景填充它,然后当它到达退出的指令时,刚才的黑色窗口几乎立即就消失了。除了 Shell 栏中的一条短信息,如下图所示。到目前为止,这个程序还没有取得什么成果。
你的程序是可运行的,但几乎什么都没做。
为了显示你的差异点图像,在pygame.quit()
上面的空白处键入以下一行:
difference = pygame.image.load('spot_the_diff.png')
为了确保图像能够填满屏幕,你需要将其缩放以符合你的显示器或电视的分辨率。输入以下内容:
difference = pygame.transform.scale(difference, (width, height))
现在图像在内存中,你需要告诉 Pygame 在屏幕上实际显示它——这个过程被称为 blitting ,或者说是位块传输(Blitting 是光栅图形中的一种标准技术,通过将所有不变的图形元素渲染到背景图像中来加速重复绘制。然后,对于每次绘制,只需要在这个背景上绘制变化的元素)。输入以下内容:
screen.blit(difference, (0, 0))
pygame.display.update()
其中第一行将图像复制到屏幕上,从左上角开始;第二行告诉 Pygame 重新绘制屏幕。如果没有这第二行,图像将在内存中处于正确的位置,但你永远不会看到它!
点击“Run”图标,图像将短暂地出现在屏幕上,然后快速消失,如下图所示。
你的找不同图像被显示在屏幕上。
要想更长时间地看到图像,请在 pygame.quit()
上面添加以下一行。
sleep(3)
再次点击运行,图像将在屏幕上停留更长时间。在 pygame.display.update()
这行下面输入以下内容,就可以添加你的惊喜图片。
zombie = pygame.image.load('scary_face.png')
zombie = pygame.transform.scale(zombie, (width, height))
增加一个延迟,让僵尸图像不会马上出现。
sleep(3)
然后将图像混合到屏幕上并更新,使其显示给玩家。
screen.blit(zombie, (0, 0))
pygame.display.update()
点击“Run”图标,看看会发生什么。Pygame 会先加载你的找不同图像,但三秒钟后,它将被替换成可怕的僵尸头像!如下图所示。这时,你就会发现,你的图像已经变成了一个可怕的僵尸。
它将给别人一个可怕的惊喜。
将延迟设置为三秒,这会使事情变得有点可预测。将 screen.blit(zombie, (0,0))
上面的 sleep(3)
行改为。
sleep(randrange(5, 15))
这将在5和15之间选取一个随机数,并将程序延迟那么长时间。接下来,在你的sleep 指令上方添加以下一行,以加载尖叫声文件。
scream = pygame.mixer.Sound('scream.wav')
移动到你的睡眠指令下面,在新的一行输入以下内容,开始播放声音,这样它就会在可怕的图像实际显示给玩家之前启动。
scream.play()
最后,通过在pygame.quit()
上面输入下面一行,告诉Pygame停止播放声音。
scream.stop()
点击“Run”图标,欣赏你的杰作:在进过几秒钟的找不同的乐趣之后,你的可怕的僵尸将出现在一个令人毛骨悚然的尖叫声中——肯定会给你的朋友带来惊吓。如果你发现僵尸图片在声音开始播放之前就出现了,你可以通过在scream.play()
指令之后和 screen.blit
指令之前添加一个小的延迟来补偿:
sleep(0.4)
你完成的程序应该看起来像这样:
import pygame
from pygame.locals import *
from time import sleep
from random import randrange
pygame.init()
width = pygame.display.Info().current_w
height = pygame.display.Info().current_h
screen = pygame.display.set_mode((width, height))
difference = pygame.image.load('spot_the_diff.png')
difference = pygame.transform.scale(difference, (width, height))
screen.blit(difference, (0, 0))
pygame.display.update()
zombie = pygame.image.load('scary_face.png')
zombie = pygame.transform.scale (zombie, (width, height))
scream = pygame.mixer.Sound('scream.wav')
sleep(randrange(5, 15))
scream.play()
screen.blit(zombie, (0,0))
pygame.display.update()
sleep(3)
scream.stop()
pygame.quit()
现在要做的就是邀请你的朋友来玩找不同的游戏——当然,还要确保扬声器的声音开得很大。
挑战:给游戏换皮
你能改变图片,使恶作剧更适合于其他活动,如圣诞节吗?你能不能画出你自己的找不同和可怕的图像(使用 GIMP 等图形编辑器)?你能不能跟踪用户点击的差异,使其更有说服力?
项目3:RPG 迷宫
现在你已经掌握了 Python,是时候用 Pygame 做一些更复杂的东西了:基于经典的角色扮演游戏,做一个全功能的文本迷宫游戏。这类游戏被称为文本冒险或交互式小说,可以追溯到计算机不能处理图形的时候,但仍然有他们的死忠粉认为,任何图形都不会像你想象中的那样生动!
在线项目
这个项目也可以在 rpf.io/python-rpg 网上找到。
这个程序比本章中的其他程序要复杂得多,所以为了使事情变得更容易,你将从一个已经部分写好的版本开始。打开 Chromium 网络浏览器,并输入以下网址:rpf.io/rpg-code。
Chromium 网络浏览器会自动将程序的代码下载到你的 Downloads 文件夹中,但会警告你该文件的类型——Python 程序——可能会伤害你的计算机。你已经从树莓派基金会下载了这个文件,这是一个值得信赖的来源,所以点击屏幕下方出现的警告信息的保留按钮。回到 Thonny,然后点击“ Load”图标。在你的 Downloads 文件夹中找到文件,rpg-rpg.py,然后点击加载按钮。
点击“Run”图标开始,熟悉一下文字冒险游戏的运作方式。游戏的输出出现在 Thonny 窗口底部的 Shell 区域;通过点击最大化按钮使 Thonny 窗口变大,以使其更容易阅读。
现在的游戏非常简单:有两个 room (房间),没有 item (物体)。玩家从 Hall(大厅)开始,这是两个房间中的第一个。要去 Kitchen,(厨房),只需输入“go south”,然后按回车键,如下图所示。当你在厨房的时候,你可以输入“go north”来返回大厅。你也可以试着输入“go west”和“go east”,但由于这些方向上没有任何房间,游戏会显示错误信息。
到目前为止只有两个房间。
向下滚动到脚本区程序的第29行,可以找到一个叫做 “room(房间)”的变量。这种类型的变量被称为 dictionary(字典),它定义了游戏中的房间、房间的出口,以及某个出口通往哪个房间。
为了使游戏更加有趣,我们尝试增加一个房间:把餐厅(Dining Room)放在大厅的东边。在脚本区找到房间变量,在第38行的}后面加上一个,
,然后输入以下内容(在字典中准确的缩进不是必须的),来扩展它:
'Dining Room' : {
'west' : 'Hall'
}
你还需要在大厅里添加一个新的出口,因为并没有自动为你创建。在第33行的末尾,加上一个,
,然后加上以下一行。
'east' : 'Dining Room'
点击“Run”图标,试试你的新房间:在大厅里输入“go east”,进入餐厅(如下图所示),在餐厅里输入 “go west”,进入大厅。恭喜你:你已经建立了一个属于你自己的房间!
你已经增加了一个房间。
不过,空荡荡的房间并不怎么有趣。要在一个房间里增加一个物品,你需要修改这个房间的字典。点击“Stop”图标,停止程序。在脚本区找到大厅的字典(dictionary),然后在 'east':'Dining Room'
这一行的末尾加上一个,
,再按下回车键,输入下面一行。
'item' : 'key'
再次点击“Run”图标。这一次,游戏会告诉你,你可以看到你的新物品:一把钥匙。输入“get key”(如下图),你就可以拿起它,把它添加到你所携带的物品清单中——称为你的“库存(inventory)”。在你从一个房间到另一个房间的过程中,你的库存会一直伴随着你。
收集的钥匙被添加到你的库存中。
点击“Stop”图标 ,增加一个需要躲避的怪物,使游戏更加有趣。找到厨房词典,用添加 “钥匙”项目的方法添加一个 “怪物 “项——记得在上面一行的末尾添加一个“逗号”。
'item' : 'monster'
为了让怪物能够攻击玩家,你需要在游戏中添加一些逻辑。在脚本区滚动到程序的最底部,添加以下几行——包括用哈希符号标记的注释,如果你改天再来看,这将有助于你理解这个程序——并确保缩进这几行。
# player loses if they enter a room with a monster
if 'item' in rooms[currentRoom] and 'monster' in rooms[currentRoom]['item']:
print('A monster has got you... GAME OVER!')
break
点击“Run”图标,并尝试进入厨房房间(如下图)——当你这样做时,怪物不会留下太深刻的印象。
别管老鼠了,厨房里有个怪物。
要想把这次冒险变成一个合适的游戏,你需要更多的物品、另一个房间,以及带着所有物品安全离开房子的“胜利”能力。开始添加另一个房间,就像你为餐厅所做的那样,只是这一次,它是一个花园。从餐厅的字典中添加一个出口,记得在上面一行的末尾添加一个逗号。
'south' : 'Garden'
然后将你的新房间添加到主房间字典中,同样记得像以前一样在上面一行的}
后面添加一个,
。
'Garden' : {
'north' : 'Dining Room'
}
在Dining Room字典中添加一个'potion'
对象,同样记得在上面的一行中添加必要的逗号。
'item' : 'potion'
最后,滚动到程序的底部,添加所需的逻辑,以检查玩家是否拥有所有的物品,如果是的话,告诉他们他们已经赢得了游戏。
# player wins if they get to the garden with a key and a potion
if currentRoom == 'Garden' and 'key' in inventory and
'potion' in inventory:
print('You escaped the house... YOU WIN!')
break
点击 “Run”图标,并尝试在去花园之前拿起钥匙和药水来完成游戏。记住不要进入厨房的房间,因为那是怪物所在的地方!
作为游戏的最后一个调整,添加一些指示,告诉玩家如何完成游戏。滚动到程序的顶部,在定义函数showInstructions()
的地方,添加以下内容。
Get to the garden with a key and a potion
Avoid the monsters!
(带着钥匙和药水到花园去,
避开那些怪物!)
最后一次运行游戏,你会看到你的新指令出现在最开始的位置(见下图)。
恭喜你:你已经制作了一个基于文本的互动迷宫游戏
现在玩家知道他们需要做什么了。
挑战:扩展游戏
你能添加更多的房间,使游戏持续更长时间吗?你能不能增加一件物品来保护你不被怪物吃掉?你会如何添加一种武器来杀死怪物?你能不能在现有房间的上方和下方增加房间,通过楼梯进入?