俄罗斯方块Tetris(tkinter)
本帖最后由 pyzyd 于 2025-7-21 12:35 编辑代码实现:
感觉写了一坨屎山{:10_282:}
源代码:
import tkinter as tk
from tkinter import messagebox
import random
import time
class Game(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title('Tetris')
# 固定边框
self.resizable(False,False)
# 设置边长、像素
self.width = 12
self.height = 20
self.px = 30
# 设置不同形状的格子
self.shapes = {
'O': [(-1, -1), (0, -1), (-1, 0), (0, 0)],
'I': [(0, 1), (0, 0), (0, -1), (0, -2)],
'T': [(-1, -1), (0, -1), (0, 0), (1, -1)],
'Z': [(-1, 0), (0, 0), (0, 1), (1, 1)],
'S': [(-1, 1), (0, 1), (0, 0), (1, 0)],
'L': [(1, 1), (0, 1), (0, 0), (0, -1)],
'J': [(-1, 1), (0, 1), (0, 0), (0, -1)],
}
# 设置不同格子的颜色
self.colors = ['#FF0000', '#FF7F00', "#D4D432", "#00FF00", "#0000FF", '#4B008B', "#D3007F"]
self.shape_index = random.choice(list(self.shapes.keys()))
self.shape_color = random.choice(self.colors)
self.shape = self.shapes
# 表示固定的格子
self.fixed_shape = {}
self.fixed_set = set()
# 创建画布
self.canvas = tk.Canvas(
self, width=self.width*self.px,
height=self.height*self.px)
self.canvas.grid(row=0,column=0,columnspan=3,rowspan=4, padx=10, pady=10)
self.btnr = tk.Button(self, text='<', command=lambda:self.move((-1, 0)))
self.btnr.grid(row=4, column=0, padx=10, pady=10, sticky='nsew')
self.btn_rotate = tk.Button(self, text='-', command=self.rotate_shape)
self.btn_rotate.grid(row=4, column=1, padx=10, pady=10, sticky='nsew')
self.btnd = tk.Button(self, text='v', command=lambda:self.move((0, 1)))
self.btnd.grid(row=5, column=1, padx=10, pady=10, sticky='nsew')
self.btnl = tk.Button(self, text='>', command=lambda:self.move((1, 0)))
self.btnl.grid(row=4, column=2, padx=10, pady=10, sticky='nsew')
self.score = 0
self.v = tk.StringVar()
self.v.set(f'当前分数:{self.score}')
self.label1 = tk.Label(self, textvariable=self.v,font=('微软雅黑', 24))
self.label1.grid(row=0, column=3, padx=10, pady=10, sticky='nsew')
self.best_score = self.read_best_score()
self.v2 = tk.StringVar()
self.v2.set(f'最高分:{self.best_score}')
self.label2 = tk.Label(self, textvariable=self.v2,font=('微软雅黑', 24))
self.label2.grid(row=1, column=3, padx=10, pady=10, sticky='nsew')
self.text = tk.Text(self, height=10, width=20, font=('微软雅黑', 18))
self.text.grid(row=2, column=3, padx=10, pady=10, sticky='nsew')
self.text.insert(tk.END, '游戏规则:\n')
self.text.insert(tk.END, '1. 使用方向键控制方块的移动\n')
self.text.insert(tk.END, '2. 使用方向上键(Up键)旋转方块\n')
self.text.insert(tk.END, '3. 消除满行即可获得分数\n')
self.text.insert(tk.END, '4. 超出画布即游戏结束\n')
self.bind('<Left>', lambda event:self.move((-1, 0)))
self.bind('<Right>', lambda event:self.move((1, 0)))
self.bind('<Up>', lambda event:self.rotate_shape())
self.bind('<Down>', lambda event:self.move((0, 1)))
# 设置画布的点集(范围)
self.canvas_set = set()
for i in range(0, self.width):
for j in range(0, self.height):
self.canvas_set.add((i,j))
# 运行游戏
self.run_game()
# 读取最佳分数
def read_best_score(self):
"""读取最高分"""
try:
# 打开best_score.txt文件,以只读模式
with open('best_score.txt', 'r') as f:
# 读取文件内容,并转换为整数
return int(f.read())
except:
# 如果出现异常,返回0
return 0
# 定义一个方法,用于将最高分写入文件
def write_best_score(self, score):
"""写入最高分"""
# 打开文件best_score.txt,以写入模式
with open('best_score.txt', 'w') as f:
# 将最高分转换为字符串,并写入文件
f.write(str(score))
# 运行游戏
def run_game(self):
# 初始化游戏
self.initialize()
# 自动下落
self.auto_down()
# 进入主循环
self.mainloop()
def initialize(self):
"""初始化界面"""
# 绘制背景
self.draw_bg()
# 生成初始格子
self.generate_shape()
# 绘制初始
self.draw_shape(self.shape, self.x, self.y, self.shape_color)
def generate_shape(self):
"""生成新的格子"""
self.shape_index = random.choice(list(self.shapes.keys()))
self.shape_color = random.choice(self.colors)
self.shape = self.shapes
# 设置初始位置
self.x = random.randint(self.width//4, self.width//4*3)
self.y = -4
def auto_down(self):
"""自动下移"""
# 翻转方块
self.flip()
# 移动方块
self.move()
# 每隔500毫秒调用一次auto_down方法
self.after(500, self.auto_down)
def move(self, direction=(0, 1)):
"""移动格子"""
# 获取移动方向
dx, dy = direction
# 更新格子的坐标
self.x += dx
self.y += dy
# 如果格子超出边界,则回退到原来的位置
if self.is_out():
self.x -= dx
self.y -= dy
# 如果格子到达底部,则将格子固定在底部,并生成新的格子
if self.is_bottom():
# 如果格子颜色已经在固定格子的集合中,则更新该格子的坐标
if self.shape_color in self.fixed_shape:
self.fixed_shape.update([(self.x+dx,self.y+dy) for dx,dy in self.shape])
# 如果格子颜色不在固定格子的集合中,则将格子添加到固定格子的集合中
else:
self.fixed_shape = set([(self.x+dx,self.y+dy) for dx,dy in self.shape])
# 将格子的坐标添加到固定格子的集合中
for x, y in self.shape:
self.fixed_set.add((self.x + x, self.y + y))
# 生成新的格子
self.generate_shape()
def is_over(self):
"""判断游戏是否结束"""
for x, y in self.fixed_set:
if y < 0:
return True
return False
def rotate_shape(self):
"""旋转格子"""
if self.shape != self.shapes['O']:
temp = [(-dy, dx) for dx, dy in self.shape]
for dx, dy in temp:
if self.x + dx < 0:
self.x += 1
elif self.x + dx >= self.width:
self.x -= 1
# 检查旋转后的形状是否与已经固定的方块重叠
if not self.is_overlap():
self.shape = temp
def is_overlap(self):
"""检查新的格子是否与已经固定的格子重叠"""
for dx, dy in self.shape:
if (self.x + dx, self.y + dy) in self.fixed_set:
return True
return False
def is_out(self):
"""判断是否越界"""
for dx, dy in self.shape:
if self.x + dx < 0 or self.x + dx >= self.width or self.y + dy >= self.height:
return True
if self.is_overlap():
return True
return False
def is_bottom(self):
"""判断是否到底"""
for dx, dy in self.shape:
if self.y + dy == self.height - 1:
return True
if (self.x + dx, self.y + dy + 1) in self.fixed_set:
return True
return False
def flip(self):
"""更新画布"""
# 删除画布上所有元素
self.canvas.delete("all")
# 重绘元素
self.draw_bg()
y_s = self.is_delete()
if y_s:
index_y = y_s
l = len(y_s)
self.score += l * 10
self.v.set(f'当前分数:{self.score}')
if self.score > self.best_score:
self.best_score = self.score
self.v2.set(f'最高分:{self.best_score}')
self.write_best_score(self.best_score)
for shape_color, _ in self.fixed_shape.items():
temp_list = list(_)
for x, y in _:
if y < index_y:
temp_list.remove((x, y))
temp_list.append((x, y + l))
self.fixed_set.discard((x, y))
self.fixed_set.add((x, y + l))
self.fixed_shape = set(temp_list)
for shape_color, _ in self.fixed_shape.items():
for x, y in _:
self.draw_rect(x, y, shape_color)
self.draw_shape(self.shape, self.x, self.y, self.shape_color)
# 判断是否结束
if self.is_over():
# 游戏结束
self.game_over()
def draw_bg(self):
""""绘制像素"""
# 设置背景像素颜色
fill = '#CCCCCC'
outline = 'white'
px = self.px
for x, y in list(self.canvas_set):
self.draw_rect(x, y, fill, outline)
def draw_rect(self, x, y, color, outline="white"):
""""绘制像素"""
px = self.px
# 绘制像素
self.canvas.create_rectangle(
x * px, y * px,
(x + 1) * px, (y + 1) * px,
fill=color, outline=outline
)
def draw_shape(self, shape, x, y, color):
"""绘制不同的格子"""
for dx, dy in shape:
self.draw_rect(x + dx, y + dy, color)
def is_delete(self):
"""判断是否可以删除"""
y_s = []
for y in range(self.height):
if all((x, y) in self.fixed_set for x in range(self.width)):
for x in range(self.width):
self.fixed_set.remove((x, y))
for _ in self.fixed_shape.values():
_.discard((x, y))
y_s.append(y)
return y_s
def game_over(self):
"""游戏结束"""
self.canvas.create_text(
self.width * self.px / 2,
self.height * self.px / 2,
text="Game Over",
font=("Arial", 36),
fill="red"
)
self.canvas.update()
time.sleep(1)
yesno = messagebox.askyesno("提示", "是否重新开始游戏?")
self.destroy()
if yesno:
self.__init__()
if __name__ == '__main__':
game = Game()
打包好的文件:
https://wwrx.lanzoum.com/iAsuh31hj84d
密码:b5pi
挺好的{:9_232:} {:10_275:}古德 666 {:13_413:} {:9_231:} {:10_256:} 不错,支持~ {:10_297:} {:10_297:} {:10_256:} 狠狠赞!{:10_256:} 王昊扬 发表于 2025-7-21 13:22
挺好的
赞 921139987 发表于 2025-7-21 21:46
赞 历害啊 {:10_254:} gooddddddd 厉害 支持{:10_254:} 哈哈一坨屎也喜欢看