大数跨境
0
0

Python编程入门系列课程—08 弹球小游戏

Python编程入门系列课程—08 弹球小游戏 蘑菇云创造
2021-05-20
3
导读:新课时更新啦!

点击 蘑菇云创造 关注我们


第八课 弹球小游戏


系列课程:


一、学习背景



经过上节课的学习,我们了解了面向对象的编程思想,也学习了python中与类相关的知识,同时,也学会了借助tkinter库创建窗口及按钮组件等。那么在这节课上,我们将深入学习python知识,结合tkinter库,设计一个小游戏,让我们拭目以待吧!


二、学习目标



本实践项目通过编写python程序来设计一个弹球小游戏。


知识目标:

1、理解python中的逻辑运算符

2、理解列表的索引

3、掌握类的实例方法的创建


技能目标:

1、掌握使用tkinter库实现键盘交互的方法


三、学习准备



1、电脑

2、mind+编程软件


四、学习实践



在本项目中,我们将创建两个python程序,之后运行程序,通过按动键盘上的不同按钮,实现弹球小游戏的游戏效果。


1.创建一个游戏界面

2.添加小球和球拍两个角色

3.设定游戏的机制和规则


游戏玩法机制:游戏开始时,一个小球现身于窗口界面的中间,而在界面的底部是一个长方形球拍。游戏开始后,小球自动向上弹出,遇到界面的上边缘及左右两边则反弹回来。


之后我们通过键盘的左右两个方向键来控制球拍的移动,接住下落的小球。若成功接到,小球则再次向上反弹。倘若未能接住小球,使得小球与界面下边缘接触,则游戏结束,球拍和小球停止移动,并在窗口上显示“Game Over”。


任务1:创建窗口程序设计

在这个程序中,我们首先将创建一个游戏界面。通过它,我们可以回顾通过tkinter库创建并设置窗口属性的方法。为此,我们将分三步创建这个程序。首先是分析任务,之后进行程序的编写,最后运行程序并观察效果。


1、任务分析

在这个任务中,我们首先需要创建一个窗口对象作为后续的游戏界面。

整体上我们按照顺序结构的方式编写程序,具体流程如下:



2、程序编写

在正式编写程序代码之前,我们首先要创建一个项目文件及python程序文件。


STEP1:创建与保存项目文件

启动Mind+,另存项目并命名为“弹球小游戏”。


STEP2:创建与保存python文件

创建一个python程序文件“任务一.py”,双击打开。


STEP3:编写程序


import tkinter#引入GUI工具包turtle库

#创建一个界面和配置界面的一些基本属性

window = tkinter.Tk()#创建一个tk的窗口实例对象

window.title('Game')#设置窗口标题为game

window.resizable(0, 0)#通知窗口管理器调整布局大小,0,0表示不能被拉伸

window.wm_attributes('-topmost', 1)#窗口永远在前

#创建一个500x400的界面,背景色为浅绿色,边框为厚度为0

canvas = tkinter.Canvas(window, width=500, height=400, highlightthickness=0,bg='light green')

canvas.pack()#安置画布


#初始界面,画布上绘制文字

leftsigal=canvas.create_text(430,50,text='LEFT:LEFT',font=('Times',10),state='normal')

rightsigal=canvas.create_text(430,70,text='RIGHT:RIGHT',font=('Times',10),state='normal')

over=canvas.create_text(250,200,text='GAME OVER',font=('Times',30),state='hidden')


window.update()#更新界面

window.mainloop()#循环



3、程序运行

运行程序,我们看到:弹出了一个标题为“Game”的绿色背景的游戏界面,在右上方写有左移和右移的键盘按钮操作标记。



对象链接

create_text()方法

功能说明    .create_text()方法能在画布上书写文字

使用方法    画布对象.create_text(x坐标,y坐标,text=‘文字内容’,font=(‘字体’,字号),state='状态'),其中这里的状态可以是“hidden”表示隐藏文字,也可以是“normal”,表示正常显示文字。

 

举例说明    程序中,

over=canvas.create_text(250,200,text='GAME OVER',font=('Times',30),state='hidden')

表示在画布的(250,200)坐标位书写文字,内容为“GAME OVER”,字体为“Times”,字号30,状态为隐藏不可见。

leftsigal=canvas.create_text(430,50,text='LEFT:LEFT',font=('Times',10),state='normal')

rightsigal=canvas.create_text(430,70,text='RIGHT:RIGHT',font=('Times',10),state='normal')

表示在画布上书写左右转的文字标记后将内容显示出来。


任务2:添加角色程序设计

在这个程序中,我们将在刚才创建的界面上添加游戏的角色。通过它,我们可以回顾通过实例化类来创建球拍和小球对象的方法。为此,我们将分三步创建这个程序。首先是分析任务,之后进行程序的编写,最后运行程序并观察效果。


1、任务分析

在这个游戏中,我们最主要的角色是小球和球拍,因此,我们接下来将分别创建小球对象和球拍对象。而为了实现弹球,小球和球拍都将具有移动的行为,也拥有大小、颜色等属性。因此,这里,我们通过先创建小球类和球拍类,再实例化类的方式来生成这两个对象。


整体上我们按照顺序结构的方式编写程序,具体流程如下,



为了设置小球和球拍的属性和行为,编程时我们在各自的类中再创建一个init方法,在其中设置相应的属性及功能。



其中,对于矩形球拍的创建我们通过确定两个坐标点位的方式来实现,并将两个坐标点位记录下来以便后续使用,



2、程序编写

STEP1:创建与保存python文件

新建一个python程序文件“任务二.py”,双击打开。


STEP2:编写程序


向上滑动阅览

import tkinter  #引入GUI工具包turtle库


#创建一个界面和配置界面的一些基本属性

window = tkinter.Tk()#创建一个tk的窗口实例对象

window.title('Game')#设置窗口标题为game

window.resizable(0, 0)#通知窗口管理器调整布局大小,0,0表示不能被拉伸

window.wm_attributes('-topmost', 1)#窗口永远在前

#创建一个500x400的界面,背景色为浅绿色,边框为厚度为0

canvas = tkinter.Canvas(window, width=500, height=400, highlightthickness=0,bg='light green')

canvas.pack()#安置画布


#初始界面,画布上绘制文字

leftsigal=canvas.create_text(430,50,text='LEFT:LEFT',font=('Times',10),state='normal')

rightsigal=canvas.create_text(430,70,text='RIGHT:RIGHT',font=('Times',10),state='normal')

over=canvas.create_text(250,200,text='GAME OVER',font=('Times',30),state='hidden')


class Paddle:#创建球拍类

    def __init__(self,canvas,color):#创建init方法来初始化

        self.canvas=canvas #初始化canvas画布

#保存tkinter画球拍时返回的id,为后期移动屏幕上的球拍做准备,create_rectangle 画矩形,fill为球拍的颜色

        self.id=canvas.create_rectangle(0,0,150,10,fill=color)#画一个矩形并记录下它的id

        self.canvas.move(self.id,150,380)#将球拍移动至(150,380)初始位置

        self.canvas_width=self.canvas.winfo_width()#球拍的画布宽度铺满


class Ball():#创建球类

    '''创建Ball类,初始化对象,即创建对象设置属性,一个canvas也就是画图用来画一个球,一个是color,表示球的颜色

    init是在对象被创建的同时就设置属性的一种方法,Python会在创建新对象时自动调用。'''

    def __init__(self,canvas,paddle,color):#创建init方法来初始化

        self.canvas=canvas#初始化canvas

        self.paddle=paddle#初始化paddle

        '''保存tkinter画小球返回的id,为后期移动屏幕上的小球做准备,参数分别表示为:(10,10)

        表示左上角x,y坐标,(25,25)表示右下角x,y坐标,即创建一个直径为15的圆,fill为小球的填充色'''

        self.id=canvas.create_oval(10,10,25,25,fill=color)#画圆并记录下它的id

        self.canvas.move(self.id,245,100)#将小球移动到初始位置,初始位置可通过传参进行更改,有默认值


paddle = Paddle(canvas, 'blue')#创建球拍的实例

ball = Ball(canvas, paddle, 'red')#创建球的实例


window.update()#更新界面

window.mainloop()#循环



3、程序运行

运行程序,我们看到:在游戏界面上新出现了一个红色的小球和一个蓝色球拍。



对象链接

create_rectangle()方法

功能说明    create_rectangle()方法能在画布上绘制矩形

使用方法    画布对象.create_rectangle(x1,y1,x2,y2,fill=color),这里的color为颜色

举例说明    程序中,

self.id=canvas.create_rectangle(0,0,150,10,fill=color)#画一个矩形并记录下它的坐标id

表示创建一个矩形,矩形的左上角坐标为(0,0),右下角坐标为(150,10)。

create_move()方法

功能说明    create_move()方法能设定对象在画布上的坐标位。

使用方法    画布对象.create_move(self.id,x坐标,y坐标)

举例说明    程序中,

self.canvas.move(self.id,150,380)# 将球拍移动至初始位置

表示将创建的矩形对象移动到(150,380)坐标位。

width属性与winfo_width()方法

功能说明    canvas_width表示对象在画布上的宽度,canvas.winfo_width()方法表示获取画布的宽度

使用方法    canvas_width, .canvas.winfo_width()

举例说明    程序中,

self.canvas_width=self.canvas.winfo_width()#球拍的画布宽度铺满

表示将球拍的宽度铺满画布。

create_oval()方法

功能说明    create_oval()方法能在画布上绘制圆形

使用方法    create_oval(x1,y1,x2,y2,fill=color)

举例说明    程序中,

self.id=canvas.create_oval(10,10,25,25,fill=color)#画圆并记录下它的坐标id

表示创建一个圆,圆的左上角坐标为(10,10),右下角坐标为(25,25)。


任务3:设定机制程序设计

在这个程序中,我们将设定游戏的规则机制,实现完整的弹球小游戏功能。为此,我们依旧将分三步创建这个程序。首先是分析任务,之后进行程序的编写,最后运行程序并观察效果。


游戏玩法机制:游戏开始时,一个小球现身于窗口界面的中间,而在界面的底部是一个长方形球拍。游戏开始后,小球自动向上弹出,界面的上边缘及左右两边则反弹回来。


之后我们通过键盘的左右两个方向键来控制球拍的移动,接住下落的小球。若成功接到,小球则再次向上反弹。倘若未能接住小球,使得小球与界面下边缘接触,则游戏结束,球拍和小球停止移动,并在窗口上显示“Game Over”。


1、任务分析

小球和球拍我们已经成功建成了,接下来,对于球拍,为了能通过键盘按键来控制它的移动,在球拍类中我们再创建两个实现左移和右移的实例方法,并在“__init__”方法中绑定鼠标的“左移”和“右移”两个键位且分别调用相应的实例方法,同时设定它初始时静止,移速为0。



在绑定好键盘事件后,为了避免球拍在窗口上随处移动,我们可使球拍的纵坐标固定下来,仅能左右移动,同时,我们也需设定其左右移动的范围,避免跑出游戏界面。这里,我们通过添加一个draw()方法来实现。



其中,由于球拍只能左右移动,因此在与边界判别时我们只需要用其左上角和右下角的x坐标与画布的两边宽作比较,而之前我们将(x1,y1),(x2,y2)两个坐标点位记录了下来,这里判别时我们只需要再次读取x1,x2即可,



而对于边界进行判别,我们通过条件判断语句来实现,具体流程如下,




综上,对于球拍类,我们总计创建了四个实例方法来设定它的属性及功能。




在设定完球拍后,我们同样需要创建实例方法来对小球进行设定。首先,我们需要设置小球的初始移动,为了使小球在游戏开始时往上方任意位置移动,我们需要将小球初始的横向移速随机化,并设定固定的向上移速,同时,为了避免一开始游戏就结束,我们需要通过一个变量来存储小球是否碰撞到画布底部的结果。



接着,对于小球,为了使其能在碰到左侧、右侧以及上侧边缘后反弹,我们需要设定其能横向和纵向移动,活动范围为整个游戏界面,并且和球拍一样,在设定小球碰撞画布四周的情况前我们需要先读取画布上小球的坐标列表,这里我们通过draw()方法来实现。




对于小球与各界面的碰撞检测,编程时我们通过条件判断语句来实现,具体流程如下,







最后,我们还需对球拍是否成功接住小球进行判别,这里我们通过hit_paddle()实例方法来实现,具体内容及流程如下,





综上,对于小球类,我们总计创建了三个实例方法来设定它的属性及功能。




在程序的最后,由于游戏的规则在游戏开始后永久有效,因此,对于游戏的规则及界面的设定我们以永久循环的方式编写,具体流程如下,



2、程序编写

STEP1:创建与保存python文件

新建一个python程序文件“任务三.py”,双击打开。


STEP2:编写程序


向上滑动阅览

import tkinter  #引入GUI工具包turtle库

import random   #引入随机函数

import time     #引入时间库


#创建一个界面和配置界面的一些基本属性

window = tkinter.Tk()#创建一个tk的窗口实例对象

window.title('Game')#设置窗口标题为game

window.resizable(0, 0)#通知窗口管理器调整布局大小,0,0表示不能被拉伸

window.wm_attributes('-topmost', 1)#窗口永远在前

#创建一个500x400的界面,背景色为浅绿色,边框为厚度为0

canvas = tkinter.Canvas(window, width=500, height=400, highlightthickness=0,bg='light green')

canvas.pack()#安置画布


#初始界面,画布上绘制文字

leftsigal=canvas.create_text(430,50,text='LEFT:LEFT',font=('Times',10),state='normal')

rightsigal=canvas.create_text(430,70,text='RIGHT:RIGHT',font=('Times',10),state='normal')

over=canvas.create_text(250,200,text='GAME OVER',font=('Times',30),state='hidden')


class Paddle:#创建球拍类

    def __init__(self,canvas,color):#创建init方法来初始化

        self.canvas=canvas #初始化canvas画布

        # 保存tkinter画球拍时返回的id,为后期移动屏幕上的球拍做准备,create_rectangle 画矩形,fill为球拍的颜色

        self.id=canvas.create_rectangle(0,0,150,10,fill=color)#画一个矩形并记录下它的id

        self.canvas.move(self.id,150,380)# 将球拍移动至初始位置

        self.canvas_width=self.canvas.winfo_width()#球拍的画布宽度铺满

        self.x=0# 设置对象变量x,初始值为0.也就是球拍先不移动

        #在Paddle的初始化函数里面绑定两个键盘事件:

        self.canvas.bind_all("<KeyPress-Left>",self.turn_left)

        self.canvas.bind_all("<KeyPress-Right>",self.turn_right)


    #创建实例方法,是指在类中定义的函数。

    def turn_left(self,evt): #左移,evt是向系统注册的事件

        self.x=-4#左移速度为4


    def turn_right(self,evt):#右移

        self.x=4#右移速度为4


    def draw(self):

        self.canvas.move(self.id,self.x,0)#纵坐标固定,横坐标可移动

        paddle_pos=self.canvas.coords(self.id)# 获取球拍的位置坐标

        if paddle_pos[0]<=0:# 如果球拍左上角x坐标小于等于0,则停止移动

            self.x=0

        if paddle_pos[2]>=500:# 如果球拍右下角x坐标大于等于500,则停止移动

            self.x=0


class Ball():#创建球类

    '''创建Ball类,初始化对象,即创建对象设置属性,一个canvas也就是画图用来画一个球,一个是color,表示球的颜色

    init函数是在对象被创建的同时就设置属性的一种方法,Python会在创建新对象时自动调用这个函数。'''

    def __init__(self,canvas,paddle,color):#类的初始化的函数

        self.canvas=canvas#初始化canvas

        self.paddle=paddle#初始化paddle

        '''保存tkinter画小球返回的id,为后期移动屏幕上的小球做准备,参数分别表示为:(10,10)

        表示左上角x,y坐标,(25,25)表示右下角x,y坐标,即创建一个直径为15的圆,fill为小球的填充色'''

        self.id=canvas.create_oval(10,10,25,25,fill=color)#画圆并记录下它的id

        self.canvas.move(self.id,245,100)# 将小球移动到初始位置,初始位置可通过传参进行更改,有默认值

        starts=[-3,-2,-1,1,2,3]# 给一串x分量的起始值(x和y代表横坐标和纵坐标的分量)

        random.shuffle(starts)# shuffle()方法将序列的所有元素随机排序

        self.x=starts[0]# 随机混排序,赋值给对象变量x,让它起始的时候获得随机分量值,横向速度不同,引起球每次起始角度都不同

        self.y=-7 #向上移动 

        self.hit_bottom = False# 小球是否碰触到画布底部,初始值为False,即没有碰到


    def draw(self):#让球出现在主界面上

        self.canvas.move(self.id, self.x, self.y)# 让小球可以水平和垂直运动

        pos = self.canvas.coords(self.id)# coords函数通过id返回画布球的坐标列表

        # 判断小球是否撞到画布顶部或者底部,保证小球反弹回去,不消失

        if pos[3]>= 400:# 如果小球的右下角y坐标大于画布宽度,则表示小球碰到了画布底部,游戏结束

            self.hit_bottom=True

        if pos[2] >= 500:#如果小球的右下角x坐标 大于等于画布宽度,则向左移速为5

            self.x=-5

        if pos[0]<=0:#如果小球的左上角x坐标 小于等于0,则向右移速为5

            self.x=5

        if pos[1]<=0:#如果小球的左上角y坐标小于0,则向下移速为5

            self.y=5


        if self.hit_paddle(pos)==True:# 判断 球 是否碰到了 球拍,如果碰到了则使小球回弹

            self.y=-5#向上移速为5


    #该函数用于判断 球 是否碰到了 球拍,如果碰到了则使小球回弹,否则游戏结束

    def hit_paddle(self,pos):

        paddle_pos=self.canvas.coords(self.paddle.id)# 获取球拍在画布的坐标

        # 如果小球的右下角x坐标 大于等于 球拍左上角x坐标,且小球左上角x坐标 小于等于 球拍右下角x坐标

        if pos[2]>=paddle_pos[0] and pos[0]<=paddle_pos[2]:

            # 如果小球右下角y坐标 大于等于 球拍左上角y坐标,且小球右下角y坐标 小于等于 球拍右下角y坐标

            if pos[3]>=paddle_pos[1] and pos[3]<=paddle_pos[3]:

                return True#返回值为真

        else:

            return False#返回值为假


paddle = Paddle(canvas, 'blue')#创建球拍的实例

ball = Ball(canvas, paddle, 'red')#创建球的实例

while True:

    if ball.hit_bottom == False:# 如果小球没有碰到底部

        ball.draw()#调用球的draw方法

        paddle.draw()#调用球拍的draw方法

    else:

        canvas.itemconfig(over, state='normal')#修改组件属性

    window.update()#更新屏幕

    time.sleep(0.01)#程序推迟执行0.01秒




3、程序运行

STEP1:点击运行,弹出一个标题为“Game”的浅绿色窗口。


STEP2:观察窗口,一个红色的小球向上弹出,遇到界面上边缘后下落,而一个蓝色的长方形球拍停在窗口的下方。


STEP3:通过键盘上的左右两个方向键移动球拍,接住下落的小球后,小球反弹,小球撞击窗口左右两边缘后再次反弹。


STEP4:接球失败后,弹出“Game Over”文本。



知识积累

创建实例方法

功能说明    所谓实例方法,是指在类中定义的函数。该函数是一种在类的实例上定义的函数。同“__init__”方法一样,实例方法的第一个参数必须是self,并且必须包含一个self参数。事实上,“__init__”方法也是一个实例方法。

 

使用方法    

def fuctionName(self,parameterist):

    block

参数说明如下:

fuctionName:用于指定方法名,一般使用小写字母开头;

self:self参数是一个指向实例本身的引用,是必要参数,其名称可以是self以外的单词,使用self只是一个常用习惯而已。

parameterist:用于指定除self参数以外的参数,各参数间使用逗号“,”进行分隔;

block:表示方法体,是实现的具体功能

 

举例说明    程序中,

def turn_left(self,evt): #左移,evt是向系统注册的事件

    self.x=-4#左移速度为4

就是在创建实例方法,实现的具体功能是设定球拍左移的速度值。

补充说明    实例方法和Python中的函数的主要区别就是,函数实现的是某个独立的功能,而实例方法是实现类中的一个行为,是类的一部分。

shuffle()函数

功能说明    将序列的所有元素随机排序

使用方法    random.shuffle(序列)

举例说明    程序中,

random.shuffle(starts)# shuffle()函数将序列的所有元素随机排序

表示将start列表中的元素随机排序

 

列表的索引

功能说明    列表中的每个元素都有一个编号,称为索引,通过索引可以找到相应的列表中的元素。

索引是从0开始递增的,即下标为0表示第一个元素,下标为1表示第二个元素,依次类推,如下图所示,

 

 

Python比较神奇,它的索引可以是负数。这个索引从右向左计数,也就是从最后的一个元素开始计数,即最后一个元素的索引是-1,倒数第二个元素的索引值是-2,依次类推,如下图所示,

 

使用方法    变量=列表[索引]

list = [a1,a2,a3,a4,a5]

b=list[0],表示取列表中的第一个元素并赋值给变量b,

b=list[1]表示取列表中的第二个元素赋值给变量b

 

举例说明    

如果把一家酒店比作一个列表,酒店里的每个房间都可以看作是这个列表中的元素。而房间号就相当于索引,可以通过房间号找到对应的房间。

程序中,

starts=[-3,-2,-1,1,2,3]

random.shuffle(starts)

self.x=starts[0]

在一开始的列表中有-3,-2,-1,1,2,3六个元素,此时列表中的第一个元素为-3,最后一个元素为3。

之后对列表进行随机排序,使得顺序改变,再将随机排序后的列表中的第一个元素赋值为小球初始时向上的移动速度。

 

逻辑运算符

功能说明    逻辑运算符是对真和假两种布尔值进行运算,运算后的结果仍是一个布尔值,Python中的逻辑运算符主要包括and(逻辑与)、or(逻辑或)、not(逻辑非)。

使用方法    

运算符

含义

用法

and

逻辑与

a1 and a2

or

逻辑或

a1 or a2

not

逻辑非

not a1

 

表达式1

表达式2

表达式1and表达式2

表达式1or表达式2

not表达式1

True

True

True

True

False

True

False

False

True

False

False

False

False

False

True

False

True

False

True

True

 

举例说明    程序中,

if pos[3]>=paddle_pos[1] and pos[3]<=paddle_pos[3]:

    return True#返回值为真

表示如果小球的右下角y坐标≥球拍左上角y坐标,并且小球右下角y坐标≤球拍右下角y坐标,那么返回True。



对象链接

bind_all()方法

功能说明    绑定键盘事件

使用方法    对象.bind_all("<KeyPress-按键>",self.变量标记)

举例说明    程序中,

self.canvas.bind_all("<KeyPress-Left>",self.turn_left)

表示将键盘上的“Left”键绑定为左转。

 

coords()方法

功能说明    获取球拍在画布上的位置坐标

使用方法    canvas.coords()

举例说明    程序中,

paddle_pos=self.canvas.coords(self.id)# 获取球拍的位置坐标

表示获取球拍的位置坐标。

 

itemconfig()方法

功能说明    修改组件的属性

使用方法    canvas.itemconfig(需修改的变量,需修改的内容)

举例说明    程序中,

canvas.itemconfig(over, state='normal')#修改组件属性

表示将画布上over文字的更改为正常显示。


乐一乐

    至此,弹球小游戏我们就完成啦,赶紧来试一试吧,看看你能接住多少次小球呢?


五、巩固提高



项目回顾

本节课我们利用tkinter库中的Tk()函数创建了窗口对象,并结合画布组件,创建了小球和球拍对象,之后设定规则,实现了完整的弹球小游戏。


知识小结

程序

Python知识点

创建窗口程序设计

添加角色程序设计

设定机制程序设计

创建类的实例方法、列表的索引、逻辑运算符


项目拓展

让我们尝试改变小球移动的速度来增加游戏难度吧!





蘑菇云创造

微信号 : mgystem

扫码关注,了解更多



推荐阅读:



【声明】内容源于网络
0
0
蘑菇云创造
蘑菇云是DFRobot旗下专注于AI人工智能、创客、STEAM、劳动教育的科技创新教育品牌;以为中国培养下一代科技创新人才为使命,为学校提供k12全龄段科技创新教育解决方案。
内容 969
粉丝 0
蘑菇云创造 蘑菇云是DFRobot旗下专注于AI人工智能、创客、STEAM、劳动教育的科技创新教育品牌;以为中国培养下一代科技创新人才为使命,为学校提供k12全龄段科技创新教育解决方案。
总阅读1.4k
粉丝0
内容969