【6.5】弹球游戏

小时候应该都玩过弹球的游戏,下面的步骤就是如何用Python实现这个游戏

这是一个由反弹球和球拍构成的游戏,球会在屏幕上飞过来,玩家用球拍把它弹回去,如果球落在了屏幕底部,那么游戏就结束。

1.创建画布

from tkinter import *
import random
import time

tk=Tk()
tk.title("Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)
canvas=Canvas(tk,width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()

注:

  • tk.resizable(0,0),窗口大小在水平和垂直方向上都不能改变
  • tk.wm_attributes("-topmost",1)把我们的画布窗口放在所有窗口之前
  • bd=0,highlightthickness=0 画布之外没有边框
  • tk.update() 初始化

2.创建球

在上面的代码

from tkinter import *
import random
import time

后面加上

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
    def draw(self):
        pass
 
>>> ball=Ball(canvas,'red')

就出现了一个红色的球

ball=Ball(canvas,'red')
while 1:
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

放在最上面的那段代码的后面

3.让小球移动

对Ball做一点修改

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
    def draw(self):
        self.canvas.move(self.id,0,-1)

对while做一点修改:

while 1:
    ball.draw()
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

这个时候整个的代码应该是这样:

from tkinter import *
import random
import time

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
    def draw(self):
        self.canvas.move(self.id,0,-1)

tk=Tk()
tk.title("Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)
canvas=Canvas(tk,width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()

ball=Ball(canvas,'red')

while 1:
    ball.draw()
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

让小球来回反弹

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
        self.x=0
        self.y=-1
        self.canvas_height=self.canvas.winfo_height()

    def draw(self):
        self.canvas.move(self.id,self.x,self.y)
        pos=self.canvas.coords(self.id)
        if pos[1]< =0:
            self.y=1
        if pos[3]>=self.canvas_height:
            self.y=-1

注:self.canvas_height=self.canvas.winfo_height()获取画布的高度

pos=self.canvas.coords(self.id)获取对象的位置,为[x1,y1,x2,y2]分别对应左上角和右下角

改变小球的起始方向

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
        starts=[-3,-2,-1,1,2,3]
        random.shuffle(starts)
        self.x=starts[0]
        self.y=-3
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()

    def draw(self):
        self.canvas.move(self.id,self.x,self.y)
        pos=self.canvas.coords(self.id)
        if pos[1]< =0:
            self.y=3
        if pos[3]>=self.canvas_height:
            self.y=-3
        if pos[0]< =0:
            self.x=3
        if pos[2]>=self.canvas_width:
            self.x=-3

注:相当于在之前的基础上加了一个左右边界的限定

这个时候代码应该是这样的:

from tkinter import *
import random
import time

class Ball:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
        starts=[-3,-2,-1,1,2,3]
        random.shuffle(starts)
        self.x=starts[0]
        self.y=-3
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()

    def draw(self):
        self.canvas.move(self.id,self.x,self.y)
        pos=self.canvas.coords(self.id)
        if pos[1]< =0:
            self.y=3
        if pos[3]>=self.canvas_height:
            self.y=-3
        if pos[0]< =0:
            self.x=3
        if pos[2]>=self.canvas_width:
            self.x=-3

tk=Tk()
tk.title("Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)
canvas=Canvas(tk,width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()
ball=Ball(canvas,'red')

while 1:
    ball.draw()
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

4.做一个球拍

在ball的draw函数后面新起一行

class Paddle:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_rectangle(0,0,100,10,fill=color)
        self.canvas.move(self.id,200,300)

    def draw(self):
        pass

修改后面的为

paddle=Paddle(canvas,'red')
ball=Ball(canvas,'red')

while 1:
    ball.draw()
    paddle.draw()
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

5.让球拍移动

class Paddle:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_rectangle(0,0,100,10,fill=color)
        self.canvas.move(self.id,200,300)
        self.x=0
        self.canvas_width=self.canvas.winfo_width()
        self.canvas.bind_all('< KeyPress-Left>',self.turn_left)
        self.canvas.bind_all('< KeyPress-Right>',self.turn_right)

    def draw(self):
        self.canvas.move(self.id,self.x,0)
        pos=self.canvas.coords(self.id)

        if pos[0]< =0:
            self.x=0
        if pos[2]>=self.canvas_width:
            self.x=0

    def turn_left(self,evt):
        self.x=-2

    def turn_right(self,evt):
        self.x=2

6.判断小球是否碰到球拍

修改小球的init函数

class Ball:
    def __init__(self,canvas,paddle,color):
        self.canvas=canvas
        self.paddle=paddle
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
        starts=[-3,-2,-1,1,2,3]
        random.shuffle(starts)
        self.x=starts[0]
        self.y=-3
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()

    def hit_paddle(self,pos):
        paddle_pos=self.canvas.coords(self.paddle.id)
        if pos[3]>=paddle_pos[1] and pos[2]>=paddle_pos[0] and pos[0]< =paddle_pos[2]:
            return True
        else:
            return False

    def draw(self):
        self.canvas.move(self.id,self.x,self.y)
        pos=self.canvas.coords(self.id)
        if pos[1]< =0:
            self.y=3
        if pos[3]>=self.canvas_height:
            self.y=-3
        if pos[0]< =0:
            self.x=3
        if pos[2]>=self.canvas_width:
            self.x=-3
        if self.hit_paddle(pos)==True:
            self.y=-3

修改

paddle=Paddle(canvas,'red')
ball=Ball(canvas,paddle,'red')

注:下面的这个函数主要是为了判断这个球是否在球拍上

def hit_paddle(self,pos):
	paddle_pos=self.canvas.coords(self.paddle.id)
	if pos[3]>=paddle_pos[1] and pos[2]>=paddle_pos[0] and pos[0]< =paddle_pos[2]:
	    return True
	else:
	    return False

7.增加输赢因素

在ball的inif函数后面机上变量Hit_bottom

self.canvas_height=self.canvas.winfo_height()
self.canvas_width=self.canvas.winfo_width()
self.hit_bottom=False

对while出进行修改

while 1:
    if ball.hit_bottom==False:
        ball.draw()
        paddle.draw()
    tk.update_idletasks()
    tk.update()
    time.sleep(0.01)

修改ball的draw函数

if pos[3]>=self.canvas_height:
	self.hit_bottom=True

8这个游戏的最终代码为:

from tkinter import *
import random
import time

class Ball:
    def __init__(self,canvas,paddle,color):
        self.canvas=canvas
        self.paddle=paddle
        self.id=canvas.create_oval(10,10,25,25,fill=color)
        self.canvas.move(self.id,245,100)
        starts=[-3,-2,-1,1,2,3]
        random.shuffle(starts)
        self.x=starts[0]
        self.y=-3
        self.canvas_height=self.canvas.winfo_height()
        self.canvas_width=self.canvas.winfo_width()
        self.hit_bottom=False

    def hit_paddle(self,pos):
        paddle_pos=self.canvas.coords(self.paddle.id)
        if pos[3]>=paddle_pos[1] and pos[2]>=paddle_pos[0] and pos[0]< =paddle_pos[2]:
            return True
        else:
            return False

    def draw(self):
        self.canvas.move(self.id,self.x,self.y)
        pos=self.canvas.coords(self.id)
        if pos[1]< =0:
            self.y=3
        if pos[3]>=self.canvas_height:
            self.hit_bottom=True
        if pos[0]< =0:
            self.x=3
        if pos[2]>=self.canvas_width:
            self.x=-3
        if self.hit_paddle(pos)==True:
            self.y=-3

class Paddle:
    def __init__(self,canvas,color):
        self.canvas=canvas
        self.id=canvas.create_rectangle(0,0,100,10,fill=color)
        self.canvas.move(self.id,200,300)
        self.x=0
        self.canvas_width=self.canvas.winfo_width()
        self.canvas.bind_all('< KeyPress-Left>',self.turn_left)
        self.canvas.bind_all('< KeyPress-Right>',self.turn_right)

    def draw(self):
        self.canvas.move(self.id,self.x,0)
        pos=self.canvas.coords(self.id)
        if pos[0]< =0:
            self.x=0
        if pos[2]>=self.canvas_width:
            self.x=0

    def turn_left(self,evt):
        self.x=-2
    def turn_right(self,evt):
        self.x=2

tk=Tk()
tk.title("Game")
tk.resizable(0,0)
tk.wm_attributes("-topmost",1)

canvas=Canvas(tk,width=500,height=400,bd=0,highlightthickness=0)
canvas.pack()
tk.update()

paddle=Paddle(canvas,'red')
ball=Ball(canvas,paddle,'red')

while 1:
    if ball.hit_bottom==False:
        ball.draw()
        paddle.draw()
    tk.update_idletasks()
    tk.update()
time.sleep(0.01)

参考资料:

《趣学Python编程》

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn