[Python GUI]Python内置图形界面tkinter Hand-Eye Coordination--游戏实战1
游戏介绍
本文实现的是一种成为hand-eye coordination的游戏的简单实现。hand-eye coordination就是一种锻炼手眼协调控制的游戏,有些类似于别踩白块,虽然比别踩白块要简单,但是思想是一样的。
代码实现了可以通过设置画布大小和网格多少来初始化UI,并设置方块下落速度,以改变游戏难度,还可以设置方块出现多少次之后结束本次游戏。
此游戏初步实现一个简单的版本,还可继续完善,除了下面Todolist所列出的,有其他玩法,也欢迎在评论区留言讨论。
没有gif,只能靠描述了,点击上方的 START 之后开始游戏,会在第一行随机生成方块,然后一格一格往下掉,直到最后一行,继续往下掉就消失;或者是在下落的途中,有点击事件也会消失。
关键词
Hand-Eye Coordination
Tkinter,Canvas,Button,after
TodoList
- 设置画布大小
- 设置网格多少
- 设置移动速度
- 循环次数,默认无限次
- 改成界面设置参数
- 加个计算分数的功能
- 增加方块的数量,随机颜色
- 打包
改变玩法:
- 可以改成全屏随机出现方块
- 方块换仓图片就是打地鼠
代码详解
个人感觉代码注释的已经很清楚了,就不在多余去解释了。
就在这里讲讲设计思想和函数的作用吧。__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()
代码还有可以优化和完善的地方,留待日后无聊的时候再说吧!