Pinball Example 2.0

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()

Guess you like

Origin blog.csdn.net/weixin_56043516/article/details/128103866