本帖最后由 木子呢 于 2021-11-9 16:46 编辑
第六课 飞机大战彩蛋版
一、学习背景
经过上节课的学习,我们了解了python中全局变量global以及break语句的使用,也了解了在turtle库中添加图片造型的方式。在上节课中,我们设计了一个飞机大战的小游戏,这节课,我们将在此基础上添加更多的设定,使游戏更加有趣起来!
二、学习目标
本实践项目通过编写python程序来设计一个彩蛋版的飞机大战小游戏。
知识目标:
1、理解python中的关键字 2、掌握取余算术运算符的使用 3、掌握多分支结构的使用
技能目标:
1、通过turtle库给对象切换图片造型的方式
三、学习准备
1、电脑 2、mind+编程软件
四、学习实践
在本项目中,我们将创建两个python程序,之后运行程序,通过按下键盘上的不同按钮,实现飞机大战的游戏效果。
1.创建一个屏幕和飞机、子弹、敌机、彩蛋等对象并设置其初始条件。
2.设定按键触发及游戏机制。
游戏玩法机制:敌机从屏幕上方向下飞行侵略我方领地,我方派出飞机迎敌,通过键盘上的四个方向键控制飞机的移动,空格键发射子弹,消灭敌机。若敌机与我方飞机相撞,则游戏结束。同时,若飞机发射的子弹击中飘动的彩蛋,则升级飞机的性能和子弹的威力。
任务1:初始化游戏程序设计
在这个程序中,我们将创建飞机、子弹、敌机和彩蛋对象,并对其进行初始条件设置。通过它,我们可以了解通过turtle库给对象切换图片造型的方式。为此,我们将分三步创建这个程序。首先是分析任务,之后进行程序的编写,最后运行程序并观察效果。
1、任务分析
在这个任务中,我们首先需要创建一个屏幕,之后创建出飞机大战所需的各个角色——飞机、子弹、彩蛋以及敌机并对其进行初始化设置,具体流程如下:
由于敌机的数量众多,因此,我们可以通过列表循环的方式创建并设置它,分别如下左图和右图,
对于其中显示敌机造型部分,由于有两张不同的造型图,因此,我们在生成时可以进行切换,这里我们通过取余的方式来实现,当余数为1时采用造型图1,当余数为0时采用另一张造型图,而对两个余数的判断,我们能以双分支结构来实现,流程图如下,
2、程序编写
在正式编写程序代码之前,我们首先要创建一个项目文件及python程序文件,并提前导入好gif图片(下载链接见附录1)。
STEP1:创建与保存项目文件 启动Mind+,另存项目并命名为“飞机大战彩蛋版”。
STEP2:创建与保存python文件 创建一个python程序文件“任务一.py”,双击打开。
STEP3:导入图片 在项目文件夹中导入需要的gif图。(图片与程序文件同在项目文件夹中)(下载链接见附录1)
STEP4:编写程序
- import turtle as t#导入turtle库并用变量t来表示
- import random as r#导入随机数库并用变量r来表示
- #屏幕
- screen = t.Screen()#赋值screen对象
- width,height = 600,720#设定宽度和高度
- screen.setup(width,height)#以设定好的宽度和高度来创建屏幕
- screen.bgpic('浩瀚银河.gif')#设置背景图
- screen.bgcolor('black')#设置背景色为黑
-
- #变量名称定义
- bulletSpeed = 50#设置子弹速度为50像素/单位时间
- enemySpeed = 3#设置敌机速度为3像素/单位时间
- planeSpeed = 20#设置飞机速度为20像素/单位时间
-
- enemyNum = 10#设置敌机数量为10
- bulletPower = 40#设置子弹威力大小为40
- s = 0#设置子弹初始状态为0,表示未发射
-
- plane = t.Pen()#新建飞机对象
- bullet = t.Pen()#新建子弹对象
- egg = t.Pen()#新建彩蛋对象
- enemy = []#新建敌机列表
- for i in range(enemyNum):#敌机列表循环
- enemy.append(t.Pen())#新建敌机对象并扩充到敌机列表中
-
- t.addshape('Plane.gif')#在turtle库中添加飞机造型0
- t.addshape('Plane1.gif')
- t.addshape('bullet.gif')#在turtle库中添加子弹造型0
- t.addshape('bullet1.gif')
- t.addshape('enemy.gif')#在turtle库中添加敌机造型0
- t.addshape('enemy1.gif')
- t.addshape('boom.gif')#在turtle库中添加**效果造型图
- t.addshape('boom1.gif')
- t.addshape('boom2.gif')
- t.addshape('boom3.gif')
- t.addshape('boom4.gif')
- t.addshape('boom5.gif')
- t.addshape('egg.gif')#在turtle库中添加彩蛋造型0
-
- #飞机初始设置
- plane.penup()#抬笔
- plane.setheading(90)#设置飞机朝向向上
- plane.goto(0,-300)#使飞机移动到(0,-300)初始位置
- plane.shape('Plane.gif')#设置飞机造型
-
- #子弹初始设置
- bullet.speed(0)#设置子弹移动速度最快
- bullet.penup()#抬笔
- bullet.hideturtle()#隐形
- bullet.setheading(90)#设置子弹朝向向上
- bullet.goto(0,-400)#使子弹移动到(0,-400)初始位置
- bullet.shape('bullet.gif')#设置子弹造型
-
- #敌机初始设置
- x = 1
- for i in enemy:#敌机循环
- i.speed(0)#设置敌机速度最快
- i.penup()#抬笔
- i.setheading(-90)#设置敌机朝向向下
- i.goto(r.randint(-200,200),r.randint(350,400))#使敌机移动到屏幕上方指定范围内
- #敌机造型切换
- y = x%2#取余
- if y == 1:#余数为1
- i.shape('enemy1.gif')#设置敌机造型为图1
- x = x+1#x自增1
- else:#余数为0
- i.shape('enemy.gif')#设置敌机造型为图0
- x = x+1#x自增1
-
- #彩蛋设置
- egg.speed(0)#设置彩蛋速度最快
- egg.penup()#抬笔
- egg.setheading(90)#设置彩蛋朝向向上
- egg.goto(r.randint(-200,200),r.randint(100,300))#使彩蛋移动到指定范围内
- egg.shape('egg.gif')#设置彩蛋造型为该图
- t.exitonclick()#点击屏幕退出程序
复制代码
3、程序运行
运行程序,我们看到:弹出了一个屏幕,屏幕的下方是我们的主角——飞机,屏幕的上方,两种不同造型的敌机蓄势待发,而一个小彩蛋正飘动在星空中。
知识链接 | 关键字 知识描述 关键字又称保留字,是python中已经被赋予特定意义的一些单词,编写程序时,不可以把这些关键字作为变量、函数、库等名称来使用。 知识实例 计次循环中的“for”,分支结构中的“if”,声明全局变量的“global”,创建函数时的“def”等都是关键字,常见的python语言中的关键字可通过附录2查看。 |
知识积累 | as关键字 功能说明用as后的变量来代替as前的对象,一般用来为库指定别名。 使用方法 import 库名 as 变量 举例说明 程序中,import turtle as t,表示导入turtle库并用变量t来表示。 | 算术运算符% 功能说明 对数进行取余数的操作 使用方法 x % 数字 举例说明 程序中,y = x%2,表示对x除2后的结果进行取余操作,得到的余数存储到变量y中。 | 比较运算符== 功能说明 表示等于,用于比较判断 使用方法 if 变量 == 一个数 举例说明 程序中,if y == 1,表示判断y的值是否等于1。 |
任务2:设定机制程序设计
至此,无论是游戏窗口还是游戏的角色,我们都已经成功创建了,在接下来这个程序中,我们将设置游戏的新规则:
敌机从屏幕上方向下飞行侵略我方领地,我方派出飞机迎敌,通过键盘上的四个方向键控制飞机的移动,空格键发射子弹,消灭敌机。若敌机与我方飞机相撞,则游戏结束。同时,若飞机发射的子弹击中飘动的彩蛋,则升级飞机的性能和子弹的威力。
为此,我们依旧将分三步创建程序,首先是任务分析,之后进行程序的编写,最后运行程序体验游戏。
1、任务分析
在上个任务中,我们创建了游戏的屏幕窗口,也完成了游戏角色的创建和初始化设置。接下来为了实现按下方向键控制飞机移动,按下空格键发射子弹的功能,我们将在初始化设置的基础上创建移动和射击函数并设定键盘按键的触发与监听,
同时,为了游戏的完整性,我们还需要设定彩蛋出现的位置,判定子弹的状态和位置,设定敌机的移动判定敌机是否中弹、出屏、撞击飞机以及判定彩蛋的状态。
整体上,我们将采用顺序控制的方式编写程序,而由于游戏要始终运行,因此对于游戏中各个对象上述的操作我们将通过永久循环的方式编写,流程图如下,
其中,由于彩蛋的横坐标和纵坐标出现的位置各有三种不同的可能性,因此,在设定彩蛋出现的位置时我们以多分支结构来编写,流程图如下,
在判定子弹的状态时,由于对于子弹只有发射和未发射(s为0)两种状态,因此,我们以双分支结构的方式来编写,流程图如下:
而当子弹发射向上移动超出屏幕后(纵坐标>360),我们需要将子弹隐藏起来并再次将状态设为0,这里只有一种情况,因此我们使用单分支结构编写即可,流程图如下,
由于敌机数量众多,因此,后续对于敌机的设定和判定,我们使用列表循环的方式编写程序,流程图如下,
在彩蛋中弹时,我们切换飞机造型、隐藏彩蛋、切换子弹造型并升级子弹的威力及速度,这里只有一种情况,因此我们使用单分支结构来编写,流程图如下,
2、程序编写
STEP1:创建与保存python文件 新建一个python程序文件“任务二.py”,双击打开。
STEP2:编写程序 - import turtle as t#导入turtle库并用变量t来表示
- import random as r#导入随机数库并用变量r来表示
- #屏幕
- screen = t.Screen()#赋值screen对象
- width,height = 600,720#设定宽度和高度
- screen.setup(width,height)#以设定好的宽度和高度来创建屏幕
- screen.bgpic('浩瀚银河.gif')#设置背景图
- screen.bgcolor('black')#设置背景色为黑
-
- #变量名称定义
- bulletSpeed = 50#设置子弹速度为50像素/单位时间
- enemySpeed = 3#设置敌机速度为3像素/单位时间
- planeSpeed = 20#设置飞机速度为20像素/单位时间
-
- enemyNum = 10#设置敌机数量为10
- bulletPower = 40#设置子弹威力大小为40
- s = 0#设置子弹初始状态为0,表示未发射
-
- plane = t.Pen()#新建飞机对象
- bullet = t.Pen()#新建子弹对象
- egg = t.Pen()#新建彩蛋对象
- enemy = []#新建敌机列表
- for i in range(enemyNum):#敌机列表循环
- enemy.append(t.Pen())#新建敌机对象并扩充到敌机列表中
-
- t.addshape('Plane.gif')#在turtle库中添加飞机造型0
- t.addshape('Plane1.gif')
- t.addshape('bullet.gif')#在turtle库中添加子弹造型0
- t.addshape('bullet1.gif')
- t.addshape('enemy.gif')#在turtle库中添加敌机造型0
- t.addshape('enemy1.gif')
- t.addshape('boom.gif')#在turtle库中添加**效果造型图
- t.addshape('boom1.gif')
- t.addshape('boom2.gif')
- t.addshape('boom3.gif')
- t.addshape('boom4.gif')
- t.addshape('boom5.gif')
- t.addshape('egg.gif')#在turtle库中添加彩蛋造型0
-
- #飞机初始设置
- plane.penup()#抬笔
- plane.setheading(90)#设置飞机朝向向上
- plane.goto(0,-300)#使飞机移动到(0,-300)初始位置
- plane.shape('Plane.gif')#设置飞机造型
-
- #子弹初始设置
- bullet.speed(0)#设置子弹移动速度最快
- bullet.penup()#抬笔
- bullet.hideturtle()#隐形
- bullet.setheading(90)#设置子弹朝向向上
- bullet.goto(0,-400)#使子弹移动到(0,-400)初始位置
- bullet.shape('bullet.gif')#设置子弹造型
-
- #敌机初始设置
- x = 1
- for i in enemy:#敌机循环
- i.speed(0)#设置敌机速度最快
- i.penup()#抬笔
- i.setheading(-90)#设置敌机朝向向下
- i.goto(r.randint(-200,200),r.randint(350,400))#使敌机移动到屏幕上方指定范围内
- #敌机造型切换
- y = x%2#取余
- if y == 1:#余数为1
- i.shape('enemy1.gif')#设置敌机造型为图1
- x = x+1#x自增1
- else:#余数为0
- i.shape('enemy.gif')#设置敌机造型为图0
- x = x+1#x自增1
-
- #彩蛋设置
- egg.speed(0)#设置彩蛋速度最快
- egg.penup()#抬笔
- egg.setheading(90)#设置彩蛋朝向向上
- egg.goto(r.randint(-200,200),r.randint(100,300))#使彩蛋移动到指定范围内
- egg.shape('egg.gif')#设置彩蛋造型为该图
-
- #函数定义
- #plane上下左右移动
- def leftMove():#创建左移函数
- plane.goto(plane.xcor()-planeSpeed,plane.ycor())#使飞机移动到左侧一小段距离处,这段距离值为飞机的速度值
-
- def rightMove():#创建右移函数
- plane.goto(plane.xcor()+planeSpeed,plane.ycor())#使飞机移动到右侧一小段距离处,这段距离值为飞机的速度值
-
- def upMove():#创建上移函数
- plane.goto(plane.xcor(),plane.ycor()+10)#使飞机移动到上方10像素处
-
- def downMove():#创建下移函数
- plane.goto(plane.xcor(),plane.ycor()-10)#使飞机移动到下方10像素处
-
- #创建射击函数
- def shoot():
- bullet.goto(bullet.xcor(),bullet.ycor()+bulletSpeed)#使子弹移动到上方一小段距离处,这段距离值为子弹的速度值
- bullet.showturtle()#显示子弹
- global s#定义s为全局变量
- s = 1#设置s的值为1
-
- #键盘控制
- #上下左右控制
- t.onkeypress(leftMove,'Left')#按压键盘left键实现左移
- t.onkeypress(rightMove,'Right')#按压键盘right键实现右移
- t.onkeypress(upMove,'Up')#按压键盘up键实现上移
- t.onkeypress(downMove,'Down')#按压键盘down键实现下移
- #子弹发射控制
- t.onkeypress(shoot,'space')#按压键盘空格实现射击
- #键盘监听开始
- t.listen()
-
- #游戏设置
- while True:#永久循环
- eggX = egg.xcor()+r.randint(-40,40)#彩蛋出现的x坐标
- eggY = egg.ycor()+r.randint(-40,40)#彩蛋出现的y坐标
- if eggX > 300:#如果彩蛋的x坐标超出屏幕右侧了
- eggX = 300#使彩蛋的x坐标为300,也就是正好在屏幕的最右侧
- elif eggX < -300:#如果彩蛋的x坐标超出屏幕坐侧了
- eggX = -300#使彩蛋的x坐标为-300,也就是正好在屏幕的最左侧
- else:#否则
- eggX = eggX#使彩蛋横坐标不变
-
- if eggY > 360:#如果彩蛋的y坐标超出屏幕上方了
- eggY = 360#使彩蛋的y坐标为360,也就是正好在屏幕的最上方
- elif eggY < -360:#如果彩蛋的y坐标超出屏幕底端了
- eggY = -360#使彩蛋的y坐标为360,也就是正好在屏幕的最底端
- else:#否则
- eggY = eggY#使彩蛋纵坐标不变
- egg.goto(eggX,eggY)#使彩蛋出现在该坐标位
- if s == 0:#子弹状态为0(未发射)
- bullet.goto(plane.xcor(),plane.ycor()-100)#不发射子弹
- else:#否则
- bullet.goto(bullet.xcor(),bullet.ycor()+bulletSpeed)#发射子弹
-
- if bullet.ycor() > 360:#子弹出屏(位置)
- bullet.hideturtle()#隐藏子弹
- s = 0#设置子弹状态为0(未发射)
-
- for i in enemy:#敌机列表循环
- i.goto(i.xcor(),i.ycor()-enemySpeed)#使敌机移动到下方一小段距离处,这段距离值为子弹的速度值
- #子弹打到敌机
- if i.distance(bullet) < bulletPower:#如果敌机到子弹的距离值小于子弹的威力值
- i.shape('boom.gif')#显示**效果图
- i.shape('boom1.gif')
- i.shape('boom2.gif')
- i.shape('boom3.gif')
- i.shape('boom4.gif')
- i.shape('boom5.gif')
- i.goto(r.randint(-200,200),r.randint(350,400))#使敌机移动到屏幕上方指定范围内
- #敌机造型切换
- y = x%2
- if y == 1:
- i.shape('enemy1.gif')
- x = x+1
- else:
- i.shape('enemy.gif')
- x = x+1
- bullet.hideturtle()#隐藏子弹
- s = 0#设置子弹状态为0
- if i.ycor() < -360:#敌机出屏(位置)
- i.goto(r.randint(-200,200),r.randint(350,400))#使敌机移动到屏幕上方指定范围内
- #敌机撞击
- if i.distance(plane)<50:#如果敌机与飞机的距离值小于50
- print ('game over')#打印显示游戏结束
- screen.clear()#清屏
- break#跳出列表循环
- #彩蛋中弹
- if egg.distance(bullet) < bulletPower:#如果彩蛋与子弹的距离值小于子弹的威力值
- plane.shape('Plane1.gif')#切换飞机造型为图1
- egg.hideturtle()#隐藏彩蛋
- bullet.shape('bullet1.gif')#切换子弹造型为图1
- bulletPower = 160#升级子弹威力值为160
- bulletSpeed =60#升级子弹的速度为60
复制代码
3、程序运行
STEP1:点击运行,屏幕上弹出一幅银河背景图。 STEP2:观察屏幕窗口,一架架敌机正从上方缓慢向下进军,战场中有一个小彩蛋随风飘扬。 STEP3:通过键盘上四个方向键移动飞机,对准敌机后,按下空格键“space”发射子弹,打中目标后,敌机炸裂。若击中彩蛋,则升级飞机和子弹。
知识积累 | 多分支结构的使用
功能说明 多分支结构用于多种不同情况下(≥3)的条件判断。
流程示意图
使用方法 if <条件表达式1>: <语句块1> elif <条件表达式2>: <语句块2> elif <条件表达式3>: <语句块3> ... else: <语句块n> 这里的语句块1是条件1成立时执行的操作,语句块2是条件2成立时要执行的操作,语句块3是条件3成立时要执行的操作,语句块n是条件都不成立时要执行的操作。当只有三种情况时,我们只需要使用“if...elif...else”即可。当条件增多时,我们通过增加“elif”来实现。
值得注意的是if和elif都需要判断表达式的真假,而else则不需要判断;另外,elif和else都必须跟if一起使用,不能单独使用。
举例说明 程序中, if eggX > 300:#如果彩蛋的x坐标超出屏幕右侧了 eggX = 300#使彩蛋的x坐标为300,也就是正好在屏幕的最右侧 elif eggX < -300:#如果彩蛋的x坐标超出屏幕坐侧了 eggX = -300#使彩蛋的x坐标为-300,也就是正好在屏幕的最左侧 else:#否则 eggX = eggX#使彩蛋横坐标不变 表示当彩蛋的横坐标>300时,执行使横坐标=300,当小于-300时,则执行使横坐标=-300,否则不改变彩蛋的横坐标。 |
乐一乐 至此,飞机大战小游戏的彩蛋版我们就完成啦,赶紧来试一试吧,看看你能击败多少敌机呢?
|
五、巩固提高
项目回顾
本节课我们利用海归绘图(turtle)库,首先创建了一个屏幕作为游戏窗口,之后创建了游戏中的飞机、敌机、子弹、彩蛋等角色并对其进行初始化设置,接下来设置键盘的按键触发及游戏规则,最后,体验游戏。
知识小结
项目拓展
尝试在此基础上继续优化,添加多个不同的彩蛋,击中每个彩蛋有着不一样的功能效果,比如彩蛋1加快子弹的速度,彩蛋2增加子弹的威力,彩蛋3加快敌机的移速,彩蛋4加快飞机的移速,同时,我们也可给我们的游戏增加得分机制,每击中一次敌机有一定的得分。这样是不是更好玩呢,自己来试一试吧!
附录
附录1gif图下载链接 链接:https://pan.baidu.com/s/1IFqb9Ja-x49K66LZmhw6JA 提取码:y9d8
附录2常见的python关键字 关键字 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | try包含可能会出现异常的语句,与except,finally结合使用 | | 用于异常语句,出现异常后始终要执行finally包含的代码块,与try,except结合使用 | | 包含捕获异常后的操作代码块,与try,finally结合使用 | | | | | | | | | | | | | | |
附件:
|