pyzyd 发表于 2025-7-21 12:32:42

俄罗斯方块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

王昊扬 发表于 2025-7-21 13:22:54

挺好的{:9_232:}

匿名鱼油 发表于 2025-7-21 13:58:26

{:10_275:}古德

冲浪的口香糖 发表于 2025-7-21 14:11:35

666

快速收敛 发表于 2025-7-21 14:34:02

{:13_413:}

Jtrump156 发表于 2025-7-21 14:47:08

{:9_231:}

某一个“天” 发表于 2025-7-21 15:33:51

{:10_256:}

小甲鱼 发表于 2025-7-21 19:50:34

不错,支持~

每一次信任 发表于 2025-7-21 21:31:41

{:10_297:}

921139987 发表于 2025-7-21 21:46:29

{:10_297:}

dingdong321 发表于 2025-7-21 23:30:44

{:10_256:}

学数学的混子 发表于 2025-7-22 08:28:46

狠狠赞!{:10_256:}

G先行 发表于 2025-7-22 10:21:38

王昊扬 发表于 2025-7-21 13:22
挺好的

G先行 发表于 2025-7-22 10:32:42

921139987 发表于 2025-7-21 21:46


gpa5031 发表于 2025-7-22 11:02:07

历害啊

kebi 发表于 2025-7-22 12:09:24

{:10_254:}

尉尉的可乐 发表于 2025-7-22 12:43:10

gooddddddd

d11111 发表于 2025-7-22 13:45:55

厉害

当下的力量 发表于 2025-7-22 18:28:31

支持{:10_254:}

kyo890814 发表于 2025-7-26 19:31:18

哈哈一坨屎也喜欢看
页: [1] 2 3 4 5
查看完整版本: 俄罗斯方块Tetris(tkinter)