[Python GUI]Python内置图形界面tkinter Eye-Hand Coordination--游戏实战1

[Python GUI]Python内置图形界面tkinter Hand-Eye Coordination--游戏实战1

游戏介绍

本文实现的是一种成为hand-eye coordination的游戏的简单实现。hand-eye coordination就是一种锻炼手眼协调控制的游戏,有些类似于别踩白块,虽然比别踩白块要简单,但是思想是一样的。
代码实现了可以通过设置画布大小和网格多少来初始化UI,并设置方块下落速度,以改变游戏难度,还可以设置方块出现多少次之后结束本次游戏。
此游戏初步实现一个简单的版本,还可继续完善,除了下面Todolist所列出的,有其他玩法,也欢迎在评论区留言讨论。
[Python GUI]Python内置图形界面tkinter Eye-Hand Coordination--游戏实战1
没有gif,只能靠描述了,点击上方的 START 之后开始游戏,会在第一行随机生成方块,然后一格一格往下掉,直到最后一行,继续往下掉就消失;或者是在下落的途中,有点击事件也会消失。

关键词

Hand-Eye Coordination
Tkinter,Canvas,Button,after

TodoList

  • 设置画布大小
  • 设置网格多少
  • 设置移动速度
  • 循环次数,默认无限次
  • 改成界面设置参数
  • 加个计算分数的功能
  • 增加方块的数量,随机颜色
  • 打包

改变玩法:

  • 可以改成全屏随机出现方块
  • 方块换仓图片就是打地鼠

代码详解

个人感觉代码注释的已经很清楚了,就不在多余去解释了。
就在这里讲讲设计思想和函数的作用吧。
[Python GUI]Python内置图形界面tkinter Eye-Hand Coordination--游戏实战1
__init__(): 初始化各个参数;
delete_rect(): 绑定在方块上的函数,作用是删除方块,即点击事件调用的函数,或者掉到底部时调用;
draw_grid(): 被init_ui调用,用来画水平线和垂直线,生成网格;
gen_square(): 生成方块,同时绑定删除事件;
init_ui(): 初始化UI,设置并固定窗口大小,设置按钮和画布大小;
move_down(): 控制方块向下运动
还有一个控制延时的函数after,是实现运动的关键;
after(ms, func): 第一个参数是延时时长,单位是毫秒;第二个参数是延时之后运行的函数。对于这个函数,网上看了一些例子,感觉都不太好理解,是我太笨了;还有一些文章说延时时间不准,这也没有去深究,毕竟这个游戏对延时时间准确度要求没那么高。

import tkinter as tk
import random
class EyeHand:
    def __init__(self, 
            canvas:tuple = (500,500), 
            grid:tuple = (10,10), 
            speed:int = 1, 
            loop:int = 10
            ) -> None:
        # 网格的数量
        self.grid = grid
        # 计算每个grid的宽高,(方便点的话,限制grid为正方形,这里可以为矩形),
        # 然后确定canvas宽高,所以,输入的宽高只是个参考值
        # 每个小格的宽高
        self.grid_w = canvas[0] // self.grid[0]
        self.grid_h = canvas[1] // self.grid[1]
        # 画布的尺寸
        self.canvas_size = (self.grid_w*self.grid[0], self.grid_h*self.grid[1])
        # 方块移动的速度 1000ms // speed
        self.speed = 1000 // speed
        # # 出现几个方块之后结束
        # self.loop = loop
        # 窗口的尺寸
        self.win_size = str(self.canvas_size[0]+40)+"x"+str(self.canvas_size[1]+120)
        self.main_win = tk.Tk()
        # 窗口名
        self.main_win.title("Eye–hand coordination")
        # 初始化UI
        self.init_ui()
        # 窗口显示
        self.mainloop = self.main_win.mainloop
        # 方块向下走的步数
        self.step = 0
        # 最大步数
        self.max_step = self.grid[1]
        # 当前是否有方块
        self.square_exists = False
        # 循环次数
        self.count = 0
        # 最大循环次数
        self.max_count = loop

    def init_ui(self) -> None :
        self.main_win.geometry(self.win_size) # 设置窗口大小
        self.main_win.resizable(0, 0) # 固定窗口大小
        self.canvas = tk.Canvas(self.main_win, 
                                bg="#999AAA", 
                                cursor="plus", 
                                height=self.canvas_size[0], 
                                width=self.canvas_size[1]
                                ) # 设置画布
        self.canvas.place(x=20, y=50)
        self.draw_grid(self.grid) # 画网格
        self.btn1 = tk.Button(self.main_win, 
                                text="START", 
                                font=("Arial", 12), 
                                width=20, 
                                height=1, 
                                command=self.gen_square
                                ) # 设置"开始游戏"按钮
        self.btn1.pack()

    def draw_grid(self, size) -> None :
        for row in range(0, size[0]+1):
            self.canvas.create_line(0, 
                                self.grid_h*row, 
                                self.canvas_size[1], 
                                self.grid_h*row
                                ) # 画水平线
        for col in range(0, size[1]+1):
            self.canvas.create_line(self.grid_w*col, 
                                0, 
                                self.grid_w*col, 
                                self.canvas_size[0]
                                ) # 画垂直线

    def gen_square(self) -> None :
        # 生成矩形的次数达到最大限制则不再生成
        if self.count >= self.max_count:
            self.count = 0 # 一次游戏结束,循环次数置0,则可以按"start"键重新开始游戏
            return
        self.step = 0 # 每次生成方块,step置0
        try:
            self.delete_rect(tk.Event) # 如果界面中有方块,先清除
        except:
            pass
        offset = random.randint(0, self.grid[0]-1) # 第一行随机位置生成方块的变化量
        r = self.canvas.create_rectangle(self.grid_w*offset, 
                                0, 
                                self.grid_w*offset+self.grid_h, 
                                self.grid_h, 
                                fill='blue',
                                tags=("rect")
                                ) # 第一行随机位置生成方块
        self.square_exists = True
        self.canvas.tag_bind( 'rect' , '<Button-1>' , self.delete_rect)
        self.canvas.after(self.speed, self.move_down) # 关键方法,.after(deley_ms, func),延迟deley_ms毫秒后,执行func函数

    def move_down(self) -> None :
        self.step += 1 # 计数向下移动次数,到底还没被点击则删除
        if self.step >= self.max_step:
            self.delete_rect(tk.Event)
        if self.square_exists: # 有方块存在,向下移动方块
            self.canvas.move('rect', 0, self.grid_h)
            self.canvas.after(self.speed, self.move_down)
        else: # 没有方块存在,生成下一个方块
            self.count += 1
            self.canvas.after(self.speed, self.gen_square)

    def delete_rect(self, event) ->None : # 删除方块
        self.canvas.delete("rect")
        self.square_exists = False
        
game = EyeHand(canvas=(500,500), grid=(5,5), speed=5, loop=10)
game.mainloop()

代码还有可以优化和完善的地方,留待日后无聊的时候再说吧!

上一篇:JavaScript隐藏显示密码实例


下一篇:使用PowerShell找出具体某个站点所使用的模板(Web Template)名称?