A while ago, I took everyone to make a simple example of pinball. Now let’s optimize and strengthen the pinball game to make the game’s functions more fun.
Pinball Game 2.0 display effect
Implementation process
1. Main loop, game canvas
2. Create a ball class and add a few actions (make the ball move, let the ball bounce back and forth, change the starting direction of the ball)
3. Create the Paddle class, add the racket, and make the racket move left and right (circular movement)
4. Create a Score class to increase the winning or losing factor (add 3 game chances)
Import modules, packages
import tkinter as tkinter
import tkinter.messagebox as mb
import random
import time
import tkinter , random , time
tkinter realizes the canvas pop-up window, random realizes random appearance, and time is responsible for waiting for sleep()
main loop
def main():
tk = tkinter.Tk()
def callback():
if mb.askokcancel("退出", "你想退出吗?"):
tk.destroy()
tk.protocol("WM_DELETE_WINDOW", callback)
canvas_width = 500
canvas_hight = 500
tk.title("弹球游戏")
tk.resizable(0, 0)
tk.wm_attributes("-topmost", 1)
canvas = tkinter.Canvas(tk, width=canvas_width, height=canvas_hight, bd=0, highlightthickness=0, bg='#00ffff')
canvas.pack()
tk.update()
score = Score(canvas, 'red')
paddle = Paddle(canvas, "red")
ball = Ball(canvas, paddle, score, "grey")
game_over_text = canvas.create_text(canvas_width / 2, canvas_hight / 2, text='游戏结束', state='hidden', fill='red',
font=(None, 18, "bold"))
introduce = '欢迎来到弹球游戏\n 按任意键开始\n'
game_start_text = canvas.create_text(canvas_width / 2, canvas_hight / 2, text=introduce, state='normal',
fill='magenta', font=(None, 18, "bold"))
while True:
if (ball.hit_bottom == False) and ball.paddle.started:
canvas.itemconfig(game_start_text, state='hidden')
ball.draw()
paddle.draw()
if ball.hit_bottom == True:
time.sleep(0.1)
canvas.itemconfig(game_over_text, state='normal')
tk.update_idletasks()
tk.update()
time.sleep(0.01)
if __name__ == '__main__':
main()
The tkinter.Tk() class creates a tk object, which is a basic window on which other things can be added
This function is used to display a message prompt box when the window close button is clicked, asking whether to close it, and clicking Yes to exit the window
protocol: Mainly used for window closing monitoring. Through this protocol, you can prompt whether you really want to close the window before closing it, so as to prevent the user from accidentally touching the window and causing data loss.
We need to add an animation loop The "main loop" is the central part of the program, generally speaking it controls most of the behavior of the program.
Our main loop currently just makes tkinter redraw the screen. This loop runs forever, asking tkinter to redraw the screen, and then rests for hundredths of a second.
If the ball has not touched the bottom and the game has not started
If the ball hits the bottom, the game is over
Create the ball class
class Ball():
def __init__(self, canvas, paddle, score, color, init_x=100, init_y=100):
self.canvas = canvas
self.paddle = paddle
self.score = score
self.color = color
self.id = canvas.create_oval(10, 10, 30, 30, fill=self.color)
self.canvas.move(self.id, init_x, init_y)
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 draw(self):
self.canvas.move(self.id, self.x, self.y)
position = self.canvas.coords(self.id)
if position[1] <= 0:
self.y = 3
if position[3] >= self.canvas_height:
self.hit_bottom = True
if self.hit_paddle(position) == True:
self.y = -3
if position[0] <= 0:
self.x = 3
if position[2] >= self.canvas_width:
self.x = -3
#该函数用于让小球水平和垂直运动,在运动的过程中,判断是否得分、游戏是否结束
def hit_paddle(self, position):
paddle_position = self.canvas.coords(self.paddle.id)
print('paddle_position:', paddle_position[0], paddle_position[1], paddle_position[2], paddle_position[3])
if position[2] >= paddle_position[0] and position[0] <= paddle_position[2]:
if position[3] >= paddle_position[1] and position[3] <= paddle_position[3]:
self.x += self.paddle.x
colors = ['red', 'green']
# shuffle() 方法将序列的所有元素随机排序,以便随机获得小球颜色
random.shuffle(colors)
self.color = colors[0]
self.canvas.itemconfig(self.id, fill=colors[0])
self.score.hit(ball_color=self.color)
self.canvas.itemconfig(self.paddle.id, fill=self.color)
self.adjust_paddle(paddle_position)
return True
#该函数用于判断球是否碰到了球拍,如果碰到了则使小球回弹,否则游戏结束
shuffle() 方法将序列的所有元素随机排序,以便随机获得小球颜色
return False
def adjust_paddle(self, paddle_position):
paddle_grow_length = 30
paddle_width = paddle_position[2] - paddle_position[0]
if self.color == 'red':
if paddle_width > 30:
if paddle_position[2] >= self.canvas_width:
paddle_position[2] = paddle_position[2] - paddle_grow_length
else:
paddle_position[0] = paddle_position[0] + paddle_grow_length
elif self.color == 'green':
if paddle_width < 300:
if paddle_position[2] >= self.canvas_width:
paddle_position[0] = paddle_position[0] - paddle_grow_length
else:
paddle_position[2] = paddle_position[2] + paddle_grow_length
Create the Ball class, initialize the object, that is, create the object to set the property
The init function is a way to set properties when an object is created, and Python will automatically call this function when creating a new object
Ball class initialization properties
canvas: canvas
paddle: racket
score: score
color: the color of the ball
init_x: the initial abscissa of the ball
init_y: the initial ordinate of the ball
The shuffle() method randomly sorts all elements of the sequence
winfo_height() function to get the current height of the canvas and assign it to the object variable
Whether the ball has touched the bottom of the canvas, the initial value is False, that is, it has not touched
Create the Paddle class
class Paddle:
def __init__(self, canvas, color):
self.canvas = canvas
self.canvas_width = self.canvas.winfo_width()
self.canvas_height = self.canvas.winfo_height()
self.id = canvas.create_rectangle(0, 0, 180, 15, fill=color)
self.canvas.move(self.id, 200, self.canvas_height * 0.75)
self.x = 0
self.started = False
self.continue_game = False
self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
self.canvas.bind_all('<KeyPress-Enter>', self.continue_game)
self.canvas.bind_all('<Button-1>', self.start_game)
self.canvas.bind_all('<space>', self.pause_game)
def turn_left(self, event):
position = self.canvas.coords(self.id)
if position[0] <= 0:
self.x = 0
else:
self.x = -3
def turn_right(self, event):
position = self.canvas.coords(self.id)
if position[2] >= self.canvas_width:
self.x = 0
else:
self.x = 3
#该两个函数函数用于向左(右)移动时
获取球拍的位置坐标
如果球拍的左(右)上角x坐标 小于 0
则再次按向左(右)移动时,移动距离为0
每次向左(右)移动3个像素
def start_game(self, evt):
self.started = True
def pause_game(self, evt):
if self.started:
self.started = False
else:
self.started = True
def draw(self):
self.canvas.move(self.id, self.x, 0)
position = self.canvas.coords(self.id)
if position[0] <= 0:
self.x = 0
elif position[2] >= self.canvas_width:
self.x = 0
#该函数用于移动球拍,球拍类可以水平移动
获取球拍的位置坐标,
如果球拍左上角x坐标小于等于0,则停止移动
如果球拍右下角x坐标大于等于0,则停止移动
winfo_width() function to get the current width of the canvas and assign it to the object variable
Whether to continue the game, the default value is no
Bind the event 'press the left button' and the function to move to the left when initializing
Bind the event 'press the right button' and the function to move to the right during initialization
Bind the event 'Enter key pressed' and the function to continue the game during initialization
press any key to start the game
Bind the event 'press the space key' and the function to pause the game during initialization
Create the Score class
class Score():
def __init__(self, canvas, color):
self.score = 0
self.canvas = canvas
self.canvas_width = self.canvas.winfo_width()
self.canvas_height = self.canvas.winfo_height()
self.id = canvas.create_text(self.canvas_width - 150, 10, text='score:0', fill=color, font=(None, 18, "bold"))
self.note = canvas.create_text(self.canvas_width - 70, 10, text='--', fill='red', font=(None, 18, "bold"))
def hit(self, ball_color='grey'):
self.score += 1
self.canvas.itemconfig(self.id, text='得分:{}'.format(self.score))
if ball_color == 'red':
self.canvas.itemconfig(self.note, text='{}-'.format('颜色'), fill='red')
elif ball_color == 'green':
self.canvas.itemconfig(self.note, text='{}+'.format('颜色'), fill='green')
else:
self.canvas.itemconfig(self.note, text='--', fill='grey')
Score category
canvas: canvas
color: the color of the score text
winfo_width() function to get the current width of the canvas and assign it to the object variable
Create a text control, user save user save score
Level color for user saved games
This function is used to calculate and display the score, and at the same time synchronize the color of the ball and the color of the level
Code display, copyable
import tkinter as tkinter
import tkinter.messagebox as mb
import random
import time
class Ball():
def __init__(self, canvas, paddle, score, color, init_x=100, init_y=100):
self.canvas = canvas
self.paddle = paddle
self.score = score
self.color = color
self.id = canvas.create_oval(10, 10, 30, 30, fill=self.color)
self.canvas.move(self.id, init_x, init_y)
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 draw(self):
self.canvas.move(self.id, self.x, self.y)
position = self.canvas.coords(self.id)
if position[1] <= 0:
self.y = 3
if position[3] >= self.canvas_height:
self.hit_bottom = True
if self.hit_paddle(position) == True:
self.y = -3
if position[0] <= 0:
self.x = 3
if position[2] >= self.canvas_width:
self.x = -3
def hit_paddle(self, position):
paddle_position = self.canvas.coords(self.paddle.id)
print('paddle_position:', paddle_position[0], paddle_position[1], paddle_position[2], paddle_position[3])
if position[2] >= paddle_position[0] and position[0] <= paddle_position[2]:
if position[3] >= paddle_position[1] and position[3] <= paddle_position[3]:
self.x += self.paddle.x
colors = ['red', 'green']
# shuffle() 方法将序列的所有元素随机排序,以便随机获得小球颜色
random.shuffle(colors)
self.color = colors[0]
self.canvas.itemconfig(self.id, fill=colors[0])
self.score.hit(ball_color=self.color)
self.canvas.itemconfig(self.paddle.id, fill=self.color)
self.adjust_paddle(paddle_position)
return True
return False
def adjust_paddle(self, paddle_position):
paddle_grow_length = 30
paddle_width = paddle_position[2] - paddle_position[0]
if self.color == 'red':
if paddle_width > 30:
if paddle_position[2] >= self.canvas_width:
paddle_position[2] = paddle_position[2] - paddle_grow_length
else:
paddle_position[0] = paddle_position[0] + paddle_grow_length
elif self.color == 'green':
if paddle_width < 300:
if paddle_position[2] >= self.canvas_width:
paddle_position[0] = paddle_position[0] - paddle_grow_length
else:
paddle_position[2] = paddle_position[2] + paddle_grow_length
class Paddle:
def __init__(self, canvas, color):
self.canvas = canvas
self.canvas_width = self.canvas.winfo_width()
self.canvas_height = self.canvas.winfo_height()
self.id = canvas.create_rectangle(0, 0, 180, 15, fill=color)
self.canvas.move(self.id, 200, self.canvas_height * 0.75)
self.x = 0
self.started = False
self.continue_game = False
self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
self.canvas.bind_all('<KeyPress-Enter>', self.continue_game)
self.canvas.bind_all('<Button-1>', self.start_game)
self.canvas.bind_all('<space>', self.pause_game)
def turn_left(self, event):
position = self.canvas.coords(self.id)
if position[0] <= 0:
self.x = 0
else:
self.x = -3
def turn_right(self, event):
position = self.canvas.coords(self.id)
if position[2] >= self.canvas_width:
self.x = 0
else:
self.x = 3
def start_game(self, evt):
self.started = True
def pause_game(self, evt):
if self.started:
self.started = False
else:
self.started = True
def draw(self):
self.canvas.move(self.id, self.x, 0)
position = self.canvas.coords(self.id)
if position[0] <= 0:
self.x = 0
elif position[2] >= self.canvas_width:
self.x = 0
class Score():
def __init__(self, canvas, color):
self.score = 0
self.canvas = canvas
self.canvas_width = self.canvas.winfo_width()
self.canvas_height = self.canvas.winfo_height()
self.id = canvas.create_text(self.canvas_width - 150, 10, text='score:0', fill=color, font=(None, 18, "bold"))
self.note = canvas.create_text(self.canvas_width - 70, 10, text='--', fill='red', font=(None, 18, "bold"))
def hit(self, ball_color='grey'):
self.score += 1
self.canvas.itemconfig(self.id, text='得分:{}'.format(self.score))
if ball_color == 'red':
self.canvas.itemconfig(self.note, text='{}-'.format('颜色'), fill='red')
elif ball_color == 'green':
self.canvas.itemconfig(self.note, text='{}+'.format('颜色'), fill='green')
else:
self.canvas.itemconfig(self.note, text='--', fill='grey')
def main():
tk = tkinter.Tk()
def callback():
if mb.askokcancel("退出", "你想退出吗?"):
tk.destroy()
tk.protocol("WM_DELETE_WINDOW", callback)
canvas_width = 500
canvas_hight = 500
tk.title("弹球游戏")
tk.resizable(0, 0)
tk.wm_attributes("-topmost", 1)
canvas = tkinter.Canvas(tk, width=canvas_width, height=canvas_hight, bd=0, highlightthickness=0, bg='#00ffff')
canvas.pack()
tk.update()
score = Score(canvas, 'red')
paddle = Paddle(canvas, "red")
ball = Ball(canvas, paddle, score, "grey")
game_over_text = canvas.create_text(canvas_width / 2, canvas_hight / 2, text='游戏结束', state='hidden', fill='red',
font=(None, 18, "bold"))
introduce = '欢迎来到弹球游戏\n 按任意键开始\n'
game_start_text = canvas.create_text(canvas_width / 2, canvas_hight / 2, text=introduce, state='normal',
fill='magenta', font=(None, 18, "bold"))
while True:
if (ball.hit_bottom == False) and ball.paddle.started:
canvas.itemconfig(game_start_text, state='hidden')
ball.draw()
paddle.draw()
if ball.hit_bottom == True:
time.sleep(0.1)
canvas.itemconfig(game_over_text, state='normal')
tk.update_idletasks()
tk.update()
time.sleep(0.01)
if __name__ == '__main__':
main()