游戏基本规则都实现了,先放上来,以后再完善
"""
1.本程序开发环境为python3.7,用其他版本python运行
需要修改程序
2.本程序依赖于第三方库numpy,如果没有需要自行安装
"""
from tkinter import *
from numpy import mat
import numpy as np
import time
class Block:
coords = None
speed = 20
def right(self):
translation = mat([[1,0],[1,0],[1,0],[1,0]])*self.speed
self.coords +=translation
def left(self):
translation = mat([[1, 0], [1, 0], [1, 0], [1, 0]]) * self.speed
self.coords -= translation
def down(self):
translation = mat([[0, 1], [0, 1], [0, 1], [0, 1]]) * self.speed
self.coords += translation
def rotate(self):
translation = mat([[0,1],[-1,0]])
core = self.coords[1]
for i in range(len(self)):
self.coords[i] = (self.coords[i]-core)*translation + core
def __getitem__(self, item):
return self.coords[item].tolist()[0]
def __len__(self):
return self.coords.shape[0]
class VerticalBlock(Block):
_show = [[500, 40], [500, 60], [500, 80], [500, 100]]
def __init__(self):
self.coords = mat([[200,0],[200,20],[200,40],[200,60]])
class TBlock(Block):
_show = [[480, 40], [500, 40], [500, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[200,20],[220,0]])
class SquareBlock(Block):
_show = [[480, 40], [480, 60], [500, 40], [500, 60]]
def __init__(self):
self.coords = mat([[180,0],[180,20],[200,0],[200,20]])
class LRightBlock(Block):
_show = [[480, 40], [500, 40], [520, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[220,20],[220,0]])
class LLeftBlock(Block):
_show = [[480, 40], [500, 40], [480, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[180,20],[220,0]])
class ZBlock(Block):
_show = [[480,40], [500,40], [500, 60], [520,60]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[200,20],[220,20]])
class ZMirrorBlock(Block):
_show = [[480, 60], [500, 60], [500, 40], [520, 40]]
def __init__(self):
self.coords = mat([[180,20],[200,20],[200,0],[220,0]])
class Handler:
def __init__(self,root):
self.root = root
self.canvas = Canvas(root,height=600 ,width = 600)
self.canvas.create_rectangle(0,0,400,600,fill="white")
self.scorer = Scorer(self.canvas)
self.canvas.bind("<Left>", self.move_left)
self.canvas.bind("<Right>", self.move_right)
self.canvas.bind("<Up>", self.change_shape)
self.canvas.bind("<Down>", self.accelerate)
self.canvas.focus_set()
self.canvas.pack()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.canvas.create_text(300, 300, text=f"游戏结束!您的得分为{self.scorer}", fill='red')
mainloop()
def create_block(self,name):
self.block = name()
self.create(self.block)
def paint(self, x, y):
return self.canvas.create_rectangle(x, y, x + 20, y + 20, fill='blue')
def create(self,block):
block.body = [self.paint(*block[i]) for i in range(len(block))]
def delete(self,block):
for s in block.body:
self.canvas.delete(s)
def show(self,block):
if hasattr(self,'_show'):
for item in self._show:
self.canvas.delete(item)
self._show = [self.paint(*item) for item in block._show]
def move_right(self,event):
if Rule.can_right(self.block):
self.block.right()
self.delete(self.block)
self.create(self.block)
def move_left(self,event):
if Rule.can_left(self.block):
self.block.left()
self.delete(self.block)
self.create(self.block)
def change_shape(self,event):
self.block.rotate()
self.delete(self.block)
self.create(self.block)
def move_down(self):
self.span = 0.2
while Rule.can_down(self.block):
self.block.down()
self.delete(self.block)
self.create(self.block)
time.sleep(self.span)
self.root.update()
self.record(self.block)
self.clear_full_row()
@staticmethod
def record(block):
for i in range(len(block)):
_recorder[block[i]] = block.body[i]
def clear_full_row(self):
rows = [self.block[i][1] for i in range(len(self.block))]
rows.sort()
for row in rows:
if Rule.full_row(row):
_recorder.clear_row(row,self.canvas)
self.scorer + 100
self.scorer + 10
def accelerate(self,event):
self.span = 0.1
class Recorder:
container = np.zeros((30,20))
def __setitem__(self, key, value):
x, y = key[1] // 20, key[0] // 20
self.container[x, y] = value
def __getitem__(self, item):
x, y = item[1] // 20, item[0] // 20
return self.container[x, y]
def __contains__(self, item):
x, y = item[1] // 20, item[0] // 20
return self.container[x, y]!= 0
def items_in_row(self,x):
row = x // 20
i = 0
for j in range(20):
i = i+1 if self.container[row,j]!= 0 else i
return i
def clear_row(self,x,canvas):
row = x // 20
for item in self.container[row,:]:
item = int(item)
canvas.delete(item)
for item in self.container[:row][self.container[:row]!=0]:
item = int(item)
canvas.move(item,0,20)
self.container[1:row + 1] = self.container[:row]
class Scorer:
def __init__(self,canvas):
self.score = 0
self.win = canvas
self.show_score()
def show_score(self):
self.text = self.win.create_text(500, 300, text=f"Current Score:{self.score}")
def __add__(self, other):
self.score += other
self.win.delete(self.text)
self.show_score()
def __repr__(self):
return str(self.score)
Blocks = [VerticalBlock,TBlock,SquareBlock,LRightBlock,
LLeftBlock,ZBlock,ZMirrorBlock]
_recorder = Recorder()
class Rule:
@staticmethod
def can_down(block):
for i in range(len(block)):
if block[i][1] >= 580:
return False
elif (block[i][0], block[i][1]+20) in _recorder:
return False
return True
@staticmethod
def can_right(block):
for i in range(len(block)):
if block[i][0] >360:
return False
elif (block[i][0]+20, block[i][1]) in _recorder:
return False
return True
@staticmethod
def can_left(block):
for i in range(len(block)):
if block[i][0]<20:
return False
elif (block[i][0]-20, block[i][1]) in _recorder:
return False
return True
@staticmethod
def alive():
return _recorder.items_in_row(0) == 0
@staticmethod
def full_row(y):
return _recorder.items_in_row(y) == 20
if __name__=="__main__":
root = Tk()
block = np.random.choice(Blocks)
with Handler(root) as handler:
while Rule.alive():
handler.create_block(block)
next_block = np.random.choice(Blocks)
handler.show(next_block)
handler.move_down()
block = next_block
-------------------2019-5-15更新
- 增加了进入游戏时的欢迎界面;
- 丰富了主界面;
- 修复了方块旋转时的一个BUG,增加了对可旋转条件的判断;
- 修改了加速键设置,由原来的按一次就一直加速变为长按加速,释放恢复原样。
"""
1.本程序开发环境为python3.7,用其他版本python2.X运行
需要修改程序
2.本程序依赖于第三方库numpy,如果没有需要自行安装
"""
from tkinter import *
from numpy import mat
import numpy as np
import time
class Block:
coords = None
speed = 20
def right(self):
translation = mat([[1,0],[1,0],[1,0],[1,0]])*self.speed
self.coords +=translation
def left(self):
translation = mat([[1, 0], [1, 0], [1, 0], [1, 0]]) * self.speed
self.coords -= translation
def down(self):
translation = mat([[0, 1], [0, 1], [0, 1], [0, 1]]) * self.speed
self.coords += translation
def rotate(self):
translation = mat([[0,1],[-1,0]])
core = self.coords[1]
for i in range(len(self)):
self.coords[i] = (self.coords[i]-core)*translation + core
def add_body(self,body):
self.body = body
def __getitem__(self, item):
return self.coords[item].tolist()[0]
def __len__(self):
return self.coords.shape[0]
class VerticalBlock(Block):
_show = [[500, 40], [500, 60], [500, 80], [500, 100]]
def __init__(self):
self.coords = mat([[200,0],[200,20],[200,40],[200,60]])
class TBlock(Block):
_show = [[480, 40], [500, 40], [500, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[200,20],[220,0]])
class SquareBlock(Block):
_show = [[480, 40], [480, 60], [500, 40], [500, 60]]
def __init__(self):
self.coords = mat([[180,0],[180,20],[200,0],[200,20]])
class LRightBlock(Block):
_show = [[480, 40], [500, 40], [520, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[220,20],[220,0]])
class LLeftBlock(Block):
_show = [[480, 40], [500, 40], [480, 60], [520, 40]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[180,20],[220,0]])
class ZBlock(Block):
_show = [[480,40], [500,40], [500, 60], [520,60]]
def __init__(self):
self.coords = mat([[180,0],[200,0],[200,20],[220,20]])
class ZMirrorBlock(Block):
_show = [[480, 60], [500, 60], [500, 40], [520, 40]]
def __init__(self):
self.coords = mat([[180,20],[200,20],[200,0],[220,0]])
class Recorder:
container = np.zeros((30,20))
def __setitem__(self, key, value):
if isinstance(key,tuple) or isinstance(key,list):
x = key[1] // 20
y = key[0] // 20
self.container[x, y] = value
elif isinstance(key,int):
row = key//20
self.container[row] = value
else:
a = key.start//20 if key.start!=None else None
b = key.stop//20 if key.stop!=None else None
self.container[a:b] = value
def __getitem__(self, item):
if isinstance(item,tuple):
x = item[1] // 20
y = item[0] // 20
return self.container[x, y]
elif isinstance(item,int):
row = item//20
return self.container[row]
else:
a = item.start//20 if item.start!=None else None
b = item.stop//20 if item.stop!=None else None
return self.container[a:b]
def __contains__(self, item):
x, y = item[1] // 20, item[0] // 20
return self.container[x, y]!= 0
def items_in_row(self,x):
row = x // 20
i = 0
for j in range(20):
i = i+1 if self.container[row,j]!= 0 else i
return i
def __delitem__(self, key):
row = key//20
self.container[1:row + 1] = self.container[:row]
class Scorer:
def __init__(self,canvas):
self.score = 0
self.win = canvas
self.show_score()
def show_score(self):
self.text = self.win.create_text(510, 180, text=f"{self.score}",font=('time',15))
def __add__(self, other):
self.score += other
self.win.delete(self.text)
self.show_score()
def __repr__(self):
return str(self.score)
Blocks = [VerticalBlock,TBlock,SquareBlock,LRightBlock,
LLeftBlock,ZBlock,ZMirrorBlock]
_recorder = Recorder()
class Handler:
def __init__(self,root):
self.span = 0.2
self.root = root
root.bind("<Left>", self.move_left)
root.bind("<Right>", self.move_right)
root.bind("<Up>", self.change_shape)
root.bind("<KeyPress-Down>", self.accelerate)
root.bind("<KeyRelease-Down>",self.recover)
root.focus_set()
def __enter__(self):
self.enter_interface()
self.main_interface()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.canvas.create_text(200, 300, text="GAME OVER!", fill='darkorchid',font=('Couried',30))
mainloop()
def enter_interface(self):
self.canvas = Canvas(root, height=600, width=600)
self.canvas.create_rectangle(0, 0, 600, 600, fill='black')
text = open('./note.txt').read()
self.canvas.create_text(300, 200, text=text, fill='white')
self.canvas.create_text(300, 500, text='Continue', fill='white', font=('Time', 14))
self.canvas.bind('<Button-1>', self.enter_interface_destroy)
self.canvas.pack()
root.wait_window(self.canvas)
def enter_interface_destroy(self,event):
if event.x<350 and event.x>250 and event.y>480 and event.y<520:
self.canvas.destroy()
def main_interface(self):
self.canvas = Canvas(root, height=600, width=600)
self.scorer = Scorer(self.canvas)
self.canvas.create_rectangle(0, 0, 400, 600, fill='black')
self.canvas.create_text(510, 20, text='The Next:', font=('Time', 15))
self.canvas.create_text(510, 150, text='Current Score:', font=('time', 15))
text = "Create on \r\n2019/5/15\r\nauthor:\r\nMr Lu"
self.canvas.create_text(510, 400, text=text, fill='yellow', font=('time', 15))
self.canvas.pack()
def create_block(self,name):
self.block = name()
self.create(self.block)
def paint(self, x, y):
return self.canvas.create_rectangle(x, y, x + 20, y + 20, fill=self.color, width=3)
def create(self,block):
self.color = np.random.choice(['coral','skyblue','lightgreen'])
block.add_body([self.paint(*block[i]) for i in range(len(block))])
def update(self,block):
for s in block.body:
self.canvas.delete(s)
block.add_body([self.paint(*block[i]) for i in range(len(block))])
def move(self,block,v_x,v_y):
for s in block.body:
self.canvas.move(s, v_x, v_y)
def show(self,block):
if hasattr(self,'_show'):
for item in self._show:
self.canvas.delete(item)
self._show = [self.paint(*item) for item in block._show]
def move_right(self,event):
if Rule.can_right(self.block):
self.block.right()
self.move(self.block, 20, 0)
def move_left(self,event):
if Rule.can_left(self.block):
self.block.left()
self.move(self.block, -20, 0)
def change_shape(self,event):
if Rule.can_rotate(self.block):
self.block.rotate()
self.update(self.block)
def move_down(self):
while Rule.can_down(self.block):
self.block.down()
self.move(self.block, 0, 20)
time.sleep(self.span)
self.root.update()
self.record(self.block)
self.clear_full_row()
@staticmethod
def record(block):
for i in range(len(block)):
_recorder[block[i]] = block.body[i]
def clear_full_row(self):
rows = [self.block[i][1] for i in range(len(self.block))]
rows.sort()
rows = set(rows)
for row in rows:
if Rule.full_row(row):
self.clear_row(row)
self.scorer + 100
self.scorer + 10
def clear_row(self,row):
for item in _recorder[row]:
item = int(item)
self.canvas.delete(item)
for item in _recorder[:row][_recorder[:row]!=0]:
item = int(item)
self.canvas.move(item,0,20)
del _recorder[row]
def accelerate(self,event):
self.span = 0.1
def recover(self,event):
self.span = 0.2
class Rule:
@staticmethod
def can_down(block):
for i in range(len(block)):
if block[i][1] >= 580:
return False
elif (block[i][0], block[i][1]+20) in _recorder:
return False
return True
@staticmethod
def can_right(block):
for i in range(len(block)):
if block[i][0] >360:
return False
elif (block[i][0]+20, block[i][1]) in _recorder:
return False
return True
@staticmethod
def can_left(block):
for i in range(len(block)):
if block[i][0]<20:
return False
elif (block[i][0]-20, block[i][1]) in _recorder:
return False
return True
@staticmethod
def can_rotate(block):
core = block[1]
for i in range(len(block)):
x = -block[i][1]+core[1]+core[0]
y = block[i][0]-core[0]+core[1]
if x < 0 or x > 380 or y > 580:
return False
elif (x, y) in _recorder:
return False
return True
@staticmethod
def alive():
return _recorder.items_in_row(0) == 0
@staticmethod
def full_row(y):
return _recorder.items_in_row(y) == 20
if __name__=="__main__":
root = Tk()
root.title("Tetris")
root.resizable(width=False, height=False)
block = np.random.choice(Blocks)
with Handler(root) as handler:
while Rule.alive():
handler.create_block(block)
next_block = np.random.choice(Blocks)
handler.show(next_block)
handler.move_down()
block = next_block
欢迎界面
主界面