赞
踩
目录
《俄罗斯方块》(Tetris,俄文:Тетрис)是一款由俄罗斯人阿列克谢·帕基特诺夫于1984年6月发明的休闲游戏。
该游戏曾经被多家公司代理过。经过多轮诉讼后,该游戏的代理权最终被任天堂获得。任天堂对于俄罗斯方块来说意义重大,因为将它与GB搭配在一起后,获得了巨大的成功。
《俄罗斯方块》的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。
程序中的一个核心变量是记录棋盘位置的numpy.ndarray对象grid,这里是用来记录每个格子的值,用以在前端画图的时候展示,四面的墙的值为-1,中间空间里面,空白的地方的值为0,有方块的位置的值为方块所对应的数值(大于0),程序通过判断grid里面的数值来对tkinter前端进行不同颜色的填充。
另一个非常重要的变量是this_block,表示的是当前选中的方块(BLOCK_1~BLOCK_7),每次的选择都是随机性的,BLOCK_1~BLOCK_7都是简单的类,里面主要有三个变量:BLOCK_COLOR、BLOCK_NUM、BLOCK_LOCATION,其中,BLOCK_COLOR是方块的颜色,BLOCK_NUM是方块的号码。这里最重要的是BLOCK_LOCATION,列表类型,表示的是方块的初始位置,但是由于方块会有变形这个动作,因此这里列出来了所有方块变形后对应的初始位置。同时维护一个变量change_num,通过维护change_num来改变方块的初始位置。
- self.BLOCK_1 = BLOCK_1()
- self.BLOCK_2 = BLOCK_2()
- self.BLOCK_3 = BLOCK_3()
- self.BLOCK_4 = BLOCK_4()
- self.BLOCK_5 = BLOCK_5()
- self.BLOCK_6 = BLOCK_6()
- self.BLOCK_7 = BLOCK_7()
- self.block_list = [self.BLOCK_1, self.BLOCK_2, self.BLOCK_3, self.BLOCK_4, self.BLOCK_5, self.BLOCK_6, self.BLOCK_7]
-
- self.this_block = self.block_list[random.randint(0,len(self.block_list)-1)]
方块移动的重点是维护一个变量this_block_location,表示的是当前方块的位置,所有的移动操作(方块的生成、自动下落、加速下落、左右移动、方块变形)都是对这个this_block_location进行修改。
考虑到这里的方块会有变形,因此这里的this_block_location的维护方式是这样的:首先是有一个原始的位置this_block.BLOCK_LOCATION,以及对列和对行的偏移值变量block_col_offset和block_row_offset。在自动下落、加速下落中是对block_row_offset值的修改,在左右移动中是对block_col_offset的修改,在方块的生成、方块变形中,是对方块原始位置this_block.BLOCK_LOCATION的值的修改。
This_block_location的值的构成是由this_block.BLOCK_LOCATION和block_col_offset、block_row_offset构成,构成如下:self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
方块的初始位置图如下:
另一个重点是绑定键盘事件,这里的绑定键盘事件主要有三种:
三种都是涉及到方块当前位置的更改,其中主要要考虑的是一个碰撞检验,即移动/变形后的方块位置是否没有其他的方块相撞、或者是在内部空间内。
另外还有一个重要的部分是分数的计算,在俄罗斯方块中,每次消除的得分和同时消除的行数相关
连续消除1行——100分
连续消除2行——200分
连续消除3行——400分
连续消除4行——800分
因此,这里需要判断连续消除的行数是多少。
- from tkinter import *
- from tkinter import messagebox
- import time
- import random
- import numpy as np
-
- class BLOCK_1():
- '''
- “田”字形方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [1, 0], [1, 1]]]
- self.BLOCK_COLOR = 'blue'
- self.BLOCK_NUM = 1
-
- class BLOCK_2():
- '''
- “一”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [0, 2], [0, 3]], [[-1, 0], [0, 0], [1, 0], [2, 0]]]
- self.BLOCK_COLOR = 'yellow'
- self.BLOCK_NUM = 2
-
- class BLOCK_3():
- '''
- 反“Z”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [1, 0], [-1, 1]], [[0, 1], [0, 2], [-1, 0], [-1, 1]]]
- self.BLOCK_COLOR = 'pink'
- self.BLOCK_NUM = 3
-
- class BLOCK_4():
- '''
- “L”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [0, 2], [1, 2]], [[-1, 0], [-1, 1], [0, 0], [1, 0]],
- [[1, 0], [1, 1], [1, 2], [0, 0]], [[1, 0], [1, 1], [0, 1], [-1, 1]]]
- self.BLOCK_COLOR = 'green'
- self.BLOCK_NUM = 4
-
- class BLOCK_5():
- '''
- “Z”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [1, 1], [-1, 0]], [[0, 0], [0, 1], [-1, 1], [-1, 2]]]
- self.BLOCK_COLOR = 'purple'
- self.BLOCK_NUM = 5
-
- class BLOCK_6():
- '''
- 反“L”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [0, 2], [-1, 2]], [[-1, 0], [-1, 1], [0, 1], [1, 1]],
- [[-1, 0], [-1, 1], [-1, 2], [0, 0]], [[-1, 0], [0, 0], [1, 0], [1, 1]]]
- self.BLOCK_COLOR = 'orange'
- self.BLOCK_NUM = 6
-
- class BLOCK_7():
- '''
- “T”字型方块
- '''
- def __init__(self):
- self.BLOCK_LOCATION = [[[0, 0], [0, 1], [0, 2], [-1, 1]], [[0, 0], [0, 1], [1, 1], [-1, 1]],
- [[0, 0], [0, 1], [1, 1], [0, 2]], [[-1, 1], [0, 1], [1, 1], [0, 2]]]
- self.BLOCK_COLOR = 'white'
- self.BLOCK_NUM = 7
-
- class Tetris():
- def __init__(self):
- self.width = 360 # 界面宽度
- self.height = 700 # 界面高度
- self.grid_size = 30 # 单格子边长
- self.row_num = 20 # 行数
- self.col_num = 12 # 列数
-
- self.speed = 500 # 格子下降速度
- self.total_score = 0 # 总分数
-
- self.inner_row_num = self.row_num - 2 # 内部格子空间行数
- self.inner_col_num = self.col_num - 2 # 内部格子空间列数
-
- self.grid = np.full((self.row_num, self.col_num), 0) # 记录格子空间的矩阵
- self.grid_init()
-
- self.BLOCK_1 = BLOCK_1()
- self.BLOCK_2 = BLOCK_2()
- self.BLOCK_3 = BLOCK_3()
- self.BLOCK_4 = BLOCK_4()
- self.BLOCK_5 = BLOCK_5()
- self.BLOCK_6 = BLOCK_6()
- self.BLOCK_7 = BLOCK_7()
- self.block_list = [self.BLOCK_1, self.BLOCK_2, self.BLOCK_3, self.BLOCK_4, self.BLOCK_5, self.BLOCK_6, self.BLOCK_7]
- self.color_dic = {1: self.BLOCK_1.BLOCK_COLOR, 2: self.BLOCK_2.BLOCK_COLOR, 3: self.BLOCK_3.BLOCK_COLOR,
- 4: self.BLOCK_4.BLOCK_COLOR, 5: self.BLOCK_5.BLOCK_COLOR, 6: self.BLOCK_6.BLOCK_COLOR,
- 7: self.BLOCK_7.BLOCK_COLOR, 0: 'black', -1: 'grey'} # 颜色对照表
-
- self.tk = Tk()
- self.tk.title('俄罗斯方块')
- self.tk.geometry(f'{self.width}x{self.height}')
-
- self.canvas = Canvas(self.tk, width = self.width, height = self.height, background='#FFFFFF')
- self.canvas.pack()
- self.canvas.focus_set() # 聚焦
- self.canvas.bind("<KeyPress-Left>", self.move)
- self.canvas.bind("<KeyPress-Right>", self.move)
- self.canvas.bind("<KeyPress-Down>", self.move)
- self.canvas.bind("<KeyPress-Up>", self.block_change)
-
- self.draw_grid()
-
- self.start_game()
- self.tk.mainloop()
-
- def grid_init(self):
- # 墙体赋值
- for i in range(0, self.row_num):
- self.grid[i][0] = -1
- self.grid[i][self.col_num - 1] = -1
- for i in range(0, self.col_num):
- self.grid[0][i] = -1
- self.grid[self.row_num - 1][i] = -1
-
- def draw_grid(self):
- # 画格子
- for i in range(0, self.row_num):
- for j in range(0, self.col_num):
- self.canvas.create_rectangle(j * self.grid_size + 2, i * self.grid_size + 2,
- (j + 1) * self.grid_size - 2, (i + 1) * self.grid_size - 2,
- fill=self.color_dic[self.grid[i][j]])
- self.label_text = StringVar()
- self.label_text.set('当前分数:' + str(self.total_score))
- self.label_score = Label(self.tk, textvariable=self.label_text, font=('宋体', 20), foreground='#000000', background='#FFFFFF').place_configure(x=70, y=620)
-
- def block_change(self, event):
- # 方块变形
- tmp_change_num = self.change_num + 1
- tmp_choose_one = tmp_change_num % len(self.this_block.BLOCK_LOCATION)
- tmp_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in
- self.this_block.BLOCK_LOCATION[tmp_choose_one]]
- for i in tmp_block_location:
- if self.grid[i[1], i[0]] != 0 and i not in self.this_block_location:
- return
-
- self.change_num += 1
- self.choose_one = self.change_num % len(self.this_block.BLOCK_LOCATION)
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = 0
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in
- self.this_block.BLOCK_LOCATION[self.choose_one]]
- self.canvas.delete('all')
-
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = self.this_block.BLOCK_NUM
-
- self.draw_grid()
-
- def get_random_block(self):
- # 获取随机的格子,开始下落
- self.this_block = self.block_list[random.randint(0,len(self.block_list)-1)]
- self.block_col_offset = 5
- self.block_row_offset = 1
- self.choose_one = 0
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
- self.start_judge = True
- self.change_num = 0
- if self.if_game_end():
- messagebox.showinfo('提示', '游戏结束')
- self.tk.destroy()
-
- def move(self, event):
- # 键盘事件,移动
- if event.keysym == 'Left':
- next_block_location = [[i[0] - 1, i[1]] for i in self.this_block_location]
- for i in next_block_location:
- if i not in self.this_block_location and self.grid[i[1], i[0]] != 0:
- return
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = 0
- self.block_col_offset -= 1
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
- elif event.keysym == 'Right':
- next_block_location = [[i[0] + 1, i[1]] for i in self.this_block_location]
- for i in next_block_location:
- if i not in self.this_block_location and self.grid[i[1], i[0]] != 0:
- return
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = 0
- self.block_col_offset += 1
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
- elif event.keysym == 'Down':
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = 0
- while self.if_block_end() == False:
- self.block_row_offset += 1
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
- self.canvas.delete('all')
-
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = self.this_block.BLOCK_NUM
-
- self.draw_grid()
-
- def start_game(self):
- # 开始游戏
- self.get_random_block()
- self.block_move()
-
- def block_eliminate(self):
- # 方块清除
- tmplist = self.grid.tolist()
- continuous_row = 0
- score = 0
- for i in range(1, self.inner_row_num + 1):
- tmpls = tmplist[i][1: self.inner_col_num + 1]
- if min(tmpls) > 0:
- continuous_row += 1
- for j in range(i, 1, -1):
- self.grid[j] = self.grid[j - 1]
- else:
- if continuous_row == 1:
- score += 100
- elif continuous_row == 2:
- score += 200
- elif continuous_row == 3:
- score += 400
- elif continuous_row >= 4:
- score += 800
- continuous_row = 0
- if continuous_row == 1:
- score += 100
- elif continuous_row == 2:
- score += 200
- elif continuous_row == 3:
- score += 400
- elif continuous_row >= 4:
- score += 800
- continuous_row = 0
- return score
-
- def if_game_end(self):
- # 判断游戏是否结束
- for i in self.this_block_location:
- if self.grid[i[1], i[0]] > 0:
- return True
- return False
-
- def if_block_end(self):
- # 判断方块是否下落完毕
- next_block_location = [[i[0], i[1] + 1] for i in self.this_block_location]
- for i in next_block_location:
- next_block_x = i[1]
- next_block_y = i[0]
- if i not in self.this_block_location and self.grid[next_block_x, next_block_y] != 0:
- return True
- return False
-
- def block_move(self):
- # 方块的自动下落
- if self.if_block_end() == True:
- self.total_score += self.block_eliminate()
- self.get_random_block()
-
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = 0
-
- if self.start_judge != True:
- self.block_row_offset += 1
- self.this_block_location = [[i[0] + self.block_col_offset, i[1] + self.block_row_offset] for i in self.this_block.BLOCK_LOCATION[self.choose_one]]
-
- self.canvas.delete('all')
-
- for i in self.this_block_location:
- self.grid[i[1], i[0]] = self.this_block.BLOCK_NUM
-
- self.draw_grid()
- self.start_judge = False
-
- if self.if_block_end() == False:
- self.canvas.after(self.speed, self.block_move)
- else:
- self.get_random_block()
- self.canvas.after(self.speed, self.block_move)
-
- if __name__ == '__main__':
- tetris = Tetris()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。