那时候刚好下着雨,柏油路面湿冷冷的,还闪烁着青、黄、红颜色的灯火。



用python写一个桌面弹球小游戏


用python写一个桌面弹球小游戏

学python已经有两三周的时间了,看完两本书,基础知识都已基本掌握,按照书上的例子实践一下吧,虽然书上的例子bug一大堆。我猜是作者自己也没实验过吧( ̄▽ ̄)...

游戏功能设计

游戏需要的功能就以下几个小组件

  • 一张画布
  • 一个小球
  • 一个返弹板
  • 计分
  • 控制

功能比较简单,挺没意思的,我觉得可以对接服务器,然后增加一个排行板啥的...

基于python3.5 来实现的,python2.x应该也不会差太多

窗口

制作一个大小长500px宽400px的窗口,当然我们需要导入tkinter

    from tkinter import *

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

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

小球

生成小球:

这里我们创建一个 Ball类,构造方法如下:

    def __init__(self, canvas, paddle, color):
        """
        初始化球
        :param canvas: Canvas
        :param paddle: Paddle
        :param color: string
        """
        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

创建红色小球,并把它移动到接近中间偏上的位置,随机生成好球运动的方向。同时获取窗口大小赋给变量。

返弹板

创建返弹板:

创建一个 Paddle类,构造方法如下:

    def __init__(self, canvas, color):
        """
        初始化返弹板并绑定事件
        :param canvas:
        :param 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(sequence='<KeyPress-Left>', func=self.turn_left)
        self.canvas.bind_all(sequence='<KeyPress-Right>', func=self.turn_right)

画好返弹板,并且把它移动到中间偏下的位置,获取窗口的宽度。

绑定事件,也就是监听键盘的左右键,当监听到后调用turn_leftturn_right方法

动起来

初始化好相关模块后,咱们就得开始让各个组件动起来了...

思路就是,循环移动小球的位置自己增,当遇到窗口边界时,x或y轴自增或自减,如此循环

当小球遇到返弹板的位置时x或y轴自己增或自减。

当小球的y轴等于0时,游戏结束

返弹板控制

控制返弹板向左或向右:

    def turn_left(self, event):
        """
        向左
        :return:
        """
        self.x = -2

    def turn_right(self, event):
        """
        向右
        :return:
        """
        self.x = 2

在上面的Paddle初始化的时候有绑定这两个事件...

其他

我创建了一个“锁”,目前没有想到更好的方法,就先这么做吧,当鼠标点击窗口后,开始运行程序...

class Lock:
    lock = False

    def __init__(self):
        self.lock = False

    @classmethod
    def getLock(self):
        return self.lock

    @classmethod
    def setLock(self, lock):
        self.lock = lock
        return self

锁的作用就是当你多次点击的时候不会进行操作。

start_begin 函数就是开始游戏,也就是开始让游戏动起来

使用while死循环,让程序不停的在画板上绘制出小球及画板的位置...

    def start_begin(event):
        if Lock.getLock() == True:
            return
        Lock.setLock(True)
        paddle = Paddle(canvas=canvas, color="blue")
        ball = Ball(canvas=canvas, paddle=paddle, color='red')
        time.sleep(1)
        while True:
            if ball.hit_bottom == False:
                ball.draw()
                paddle.draw()
            tk.update_idletasks()
            tk.update()
            time.sleep(0.001)

time.sleep 每0.001秒执行一次

增加计分板

张当小球成功返弹一次 分数+1,当小球的x轴等于0时,游戏结束,显示相当信息

Ball类的初始化函数增加文字信息:

    def __init__(self, canvas, paddle, color):
        """
        初始化球
        :param canvas: Canvas
        :param paddle: Paddle
        :param color: string
        """
        self.fraction = 0
        self.canvas_id = self.canvas.create_text(10, 10, anchor="nw")
        text = "得分: 0"
        self.canvas.itemconfig(self.canvas_id, fill="blue", text=text)

然后在控制球的返弹模块增加以下代码:

    def hit_paddle(self, pos):
        """
        判断返弹板
        :param pos: list
        :return: bool
        """
        paddle_pos = self.canvas.coords(self.paddle.id)
        if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
            if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
                self.fraction += 1
                self.canvas.delete(self.canvas_id)
                self.canvas_id = self.canvas.create_text(10, 10, anchor="nw")
                self.canvas.itemconfig(self.canvas_id, fill="blue", text="得分: ")
                self.canvas.insert(self.canvas_id, 12, self.fraction)
                return True
        return False

这样分数就是动态显示了...

完整代码

#!/usr/bin/env python3
# encoding: utf-8

from tkinter import *
import random
import time


class Ball:
    def __init__(self, canvas, paddle, color):
        """
        初始化球
        :param canvas: Canvas
        :param paddle: Paddle
        :param color: string
        """
        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
        self.fraction = 0
        self.canvas_id = self.canvas.create_text(10, 10, anchor="nw")
        text = "得分: 0"
        self.canvas.itemconfig(self.canvas_id, fill="blue", text=text)

    def hit_paddle(self, pos):
        """
        判断返弹板
        :param pos: list
        :return: bool
        """
        paddle_pos = self.canvas.coords(self.paddle.id)
        if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
            if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
                self.fraction += 1
                self.canvas.delete(self.canvas_id)
                self.canvas_id = self.canvas.create_text(10, 10, anchor="nw")
                self.canvas.itemconfig(self.canvas_id, fill="blue", text="得分: ")
                self.canvas.insert(self.canvas_id, 12, self.fraction)
                return True
        return False

    def draw(self):
        """

        :return:
        """
        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
            self.canvas.create_text(100, 300, text=("游戏结束! 得分: %d") % self.fraction, fill="red")
        if self.hit_paddle(pos) == True:
            self.y = -3
        if pos[0] <= 0:
            self.x = 3
        if pos[2] >= self.canvas_width:
            self.x = -3


class Paddle:
    def __init__(self, canvas, color):
        """
        初始化返弹板并绑定事件
        :param canvas:
        :param 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(sequence='<KeyPress-Left>', func=self.turn_left)
        self.canvas.bind_all(sequence='<KeyPress-Right>', func=self.turn_right)

    def turn_left(self, event):
        """
        向左
        :return:
        """
        self.x = -2

    def turn_right(self, event):
        """
        向右
        :return:
        """
        self.x = 2

    def draw(self):
        """

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


class Lock:
    lock = False

    def __init__(self):
        self.lock = False

    @classmethod
    def getLock(self):
        return self.lock

    @classmethod
    def setLock(self, lock):
        self.lock = lock
        return self


if "__main__" == __name__:
    tk = Tk()
    tk.title("Python Game")
    tk.resizable(0, 0)
    tk.wm_attributes("-topmost", 1)

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


    def start_begin(event):
        if Lock.getLock() == True:
            return
        Lock.setLock(True)
        paddle = Paddle(canvas=canvas, color="blue")
        ball = Ball(canvas=canvas, paddle=paddle, color='red')
        time.sleep(1)
        while True:
            if ball.hit_bottom == False:
                ball.draw()
                paddle.draw()
            tk.update_idletasks()
            tk.update()
            time.sleep(0.001)


    canvas.bind_all(sequence="<Button-1>", func=start_begin)

    tk.mainloop()

最终效果

视频演示

您的浏览器不支持此种视频格式。

 标签 , TAG , 啦啦