版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shuaicenglou3032/article/details/80010856
基于Python2.7,Linux下运行异常
有普通俄罗斯方块的功能以及历史最高分、暂停、重玩功能
本来是在另一台电脑上的,那台电脑不能连接u盘,故本版本是对着稳定版的代码抄的,可能哪里抄错了一些,所以存在bug.
# coding=utf-8
from Tkinter import *
from random import *
try:
import cPickle as pickle
except ImportError:
import pickle
import threading
from time import sleep
import os
#幕布类
class Curtain(object):
def __init__(self, canvas):
self.row = 20
self.col = 10
self.back = list()
self.gridBack = list()
for i in range(0, self.row):
self.back.insert(i, list())
self.gridBack.insert(i, list())
for i in range(0, self.row):
for j in range(0,self.col):
self.back[i].insert(j, 0)
self.gridBack[i].insert(j, canvas.create_rectangle(30 * j, 30 * i, 30 * (j+1), 30 * (i+1)))
#方块类
class Brick(object):
def __init__(self):
self.speed = 1 #下落速度
self.shape = 0
self.curRow = 0
self.curCol = 0
self.down = False
#生成一个新方块
def getNewBrick(self, brickConfig):
self.curBrickNum = randint(0, len(brickConfig)-1)
self.shape = 0
self.currBrick = brickConfig[self.curBrickNum][self.shape]
self.curCol = 0
self.curRow = 0
self.down = False
'''
工具类:
1.读写配置文件的形状、分数历史记录信息
2.控制程序暂停、继续、重玩
3.判断方块是否抵达边界
4.检测方块生成位置上是否有被占用的格子
'''
class Tool(object):
def __init__(self):
self.curr_dir = os.path.dirname(os.path.realpath(__file__)) #取得当前目录的路径
self.ifPause = False
self.ifRestart = False
#暂停
def pause(self):
self.ifPause = True
#继续
def continu(self):
self.ifPause = False
#重玩
def restart(self):
self.ifRestart = True
#判断是否抵达边界,左移则aspect传1,右移传3,下移传4
def checkIfArriveBorder(self, aspect, brick, back):
flag = True
if aspect == 4: #下,没到下界返回True
for i in range(0, 3):
for j in range(0, 3):
if brick.currBrick[i][j] != 0 and (
brick.curRow + i >= back.row or back.back[brick.curRow + i][brick.curCol + j] !=0):
flag = False
brick.down = True
break
elif aspect == 3: #右
for i in range(0, 3):
for j in range(0, 3):
if brick.currBrick[j][i] != 0 and (
brick.curCol + i >= back.col or back.back[brick.curRow + i][brick.curCol + j] !=0):
flag = False
break
elif aspect == 2: #上,判断变形操作是否会越界
if brick.curCol < 0:
brick.curCol = 0
if brick.curCol + 2 >= back.col:
brick.curCol = back.col - 3
if brick.curRow + 2 >= back.row:
brick.curRow = brick.curRow - 3
elif aspect == 1:
for i in range(0, 3):
for j in range(0, 3):
if brick.currBrick[i][j] != 0 and(
brick.curCol + i < 0 or back.back[brick.curRow + j][brick.curCol + i] != 0):
flag = False
break
else:
print '未知错误,aspect值=',aspect
#从文件中读取历史最高分
def getMaxGrade(self):
f = open(self.curr_dir + '/grade.txt', 'rb')
grade = pickle.load(f) # 反序列化历史最高分的信息
f.close()
return grade
#向文件中写入新的历史最高分
def updateHistoryGradeMax(self, newMax):
f = open(self.curr_dir + '/grade.txt', 'wb')
f.seek(0)
f.truncate()
pickle.dump(newMax, f)
f.close()
#从配置文件中读取方块的形状并返回读取的值
def getBrickFromConfig(self):
_configFile = open(self.curr_dir + '/config.txt', 'rb')
brick = pickle.load(_configFile)
_configFile.close()
return brick
#检测方块生成位置上是否有被占用的格子,有则返回True,并检查顶层格子是否有方块,有则游戏结束
def checkIfBeenUse(self, back, brick):
flag = False
for i in range(0,3):
for j in range(0,3):
if back.back[i][j] == 1 and brick.currBrick[i][j] == 1:
flag = True
break
if flag:
break
for i in range(0, back.col):
if back.back[0][i] == 1:
flag = True
break
return flag
class Main(object):
#实例化类和图形相关的组件
def _init__(self):
self.start = True
self.tool = Tool()
self.root = Tk()
self.HistoryScorceMax = self.tool.getMaxGrade()
self.currGrade = 0
self.brickConfig = self.tool.getBrickFromConfig()
self.ifRestart = False
self.root.title = ('俄罗斯方块v0.1')
self.root.minsize(400, 600)
self.frame = Frame(self.root, width=400, height = 600)
self.frame.place(x=0, y=0)
self.label = Label(self.root,text='历史最高分')
self.historyGradeLabel = Label(self.root,text=self.HistoryScorceMax) #显示历史最高分
self.label1 = Label(self.root,text='当前分数')
self.gameInfo = Label(self.root,text='游戏开始',fg='red',font=('times',12,'bold'))
self.currentGradeLabel = Label(self.root, text=self.currGrade)
self.button1 = Button(text='暂停', command=self.tool.pause)
self.button2 = Button(text='继续', command=self.tool.continu)
self.button3 = Button(text='重玩', command=self.tool.restart)
self.canvas = Canvas(self.frame, width=300, heigh=600)
self.button1.place(x=350, y=0)
self.button2.place(x=350, y=40)
self.button3.place(x=350, y=80)
self.label.place(x=304, y=120)
self.historyGradeLabel.place(x=369, y=120)
self.currentGradeLabel.place(x=357, y=160)
self.gameInfo.place(x=304, y=200)
self.label1.place(x=304, y=160)
self.back = Curtain(self.canvas)
self.brick = Brick()
self.canvas.pack()
#清屏并重新开始
def cleanAndRestart(self):
for i in range(0, self.back.row): #重置位置信息和颜色
for j in range(0, self.back.col):
self.back.back[i][j] = 0
self.canvas.itemconfig(self.back.gridBack[i][j],fill="white")
self.brick.getNewBrick(self.brickConfig) #重置方块
self.currGrade = 0 #重置分数
self.currentGradeLabel.config(text=self.currGrade)
self.tool.ifRestart = False
self.gameInfo.config(text="游戏开始")
#更新当前分数并对比历史最高分,若超过历史最高分刷新历史最高分并写入文件存储
def updateAndCheckGrade(self):
self.currGrade += 1
self.currentGradeLabel.config(text=self.currGrade)
if self.currGrade > self.HistoryScorceMax:
self.HistoryScorceMax = self.currGrade
self.historyGradeLabel.config(text=self.HistoryScorceMax)
self.tool.updateHistoryGradeMax(self.HistoryScorceMax)
#检查是否有需要消除的行
def checkIfNeedRemove(self):
for i in range(0, self.back.row):
tag1 = True
for j in range(0, self.back.col):
if self.back.back[i][j] == 0:
tag1 = False
break
if tag1 == True:
self.updateAndCheckGrade()
for m in xrange(i - 1, 0, -1):
for n in range(0, self.back.col):
self.back.back[m+1][n] = self.back.back[m][n]
#更新back表中的位置信息
def updateBackInfo(self):
for i in range(0, self.back.row):
for j in range(0, self.back.col):
if self.back.back[i][j] == 1:
self.canvas.itemconfig(self.back.gridBack[i][j], fill="red")
elif self.back.back[i][j] == 0:
self.canvas.itemconfig(self.back.gridBack[i][j], fill="white")
for i in range(0, len(self.brick.currBrick)):
for j in range(0, len(self.brick.currBrick[i])):
if self.brick.currBrick[i][j] == 1:
self.canvas.itemconfig(self.back.gridBack[self.brick.curRow+i][self.brick.curCol+j], fill="red")
#判断方块是否已经运动到达底部
if self.brick.down:
for i in range(0, len(self.brick.currBrick)):
for j in range(0, len(self.brick.currBrick[i])):
if self.brick.currBrick[i][j] != 0:
self.back.back[self.brick.curRow+i][self.brick.curCol+j] = self.brick.currBrick[i][j]
#检查整行是否需要消除
self.checkIfNeedRemove()
#获得下一个方块
self.brick.getNewBrick(self.brickConfig)
#处理键盘事件
def onKeyBoardEvent(self, event):
#未开始,不必监听键盘输入
if self.start == False:
return
if self.tool.ifPause: #暂停时不监听键盘操作
return
#记录原来的值
midCurCol = self.brick.curCol
midCurRow = self.brick.curRow
midShape = self.brick.shape
direction = 0
midBrick = self.brick.currBrick
if event.keycode == 37:
# 左移
self.brick.curCol -= 1
direction = 1
elif event.keycode == 38:
# 变化方块的形状
self.brick.shape += 1
direction = 2
if self.brick.shape >= 4:
self.brick.shape = 0
self.brick.currBrick = self.brickConfig[self.brick.curBrickNum][self.brick.shape]
elif event.keycode == 39:
direction = 3
# 右移
self.brick.curCol += 1
elif event.keycode == 40:
direction = 4
# 下移
self.brick.curRow += 1
if self.tool.checkIfArriveBorder(direction,self.brick,self.back):
self.brick.curCol = midCurCol
self.brick.curRow = midCurRow
self.brick.shape = midShape
self.brick.currBrick = midBrick
self.updateBackInfo()
return True
#方块向下移动的线程run方法
def brickDown(self):
while True:
if self.start == False:
print("线程退出")
break;
if self.tool.ifRestart:
print '开始重玩'
self.cleanAndRestart()
while self.tool.ifPause:
if self.tool.ifRestart:
self.cleanAndRestart() #暂停时点击重玩按钮,进入重玩流程
self.tool.ifPause = False
break
if self.tool.checkIfBeenUse(self.back,self.brick):
print('格子被占用,游戏结束')
self.gameInfo.config(text="游戏结束")
while True:
if self.tool.ifRestart:
self.cleanAndRestart()
self.tool.ifPause = False
break
else:
tempRow = self.brick.curRow
self.brick.curRow += 1
if self.tool.checkIfArriveBorder(4, self.brick, self.back) == False:
self.brick.curRow = tempRow
self.updateBackInfo()
sleep(self.brick.speed)
def __init__(self):
self._init__()
self.brick.getNewBrick(self.brickConfig)
self.downThread = threading.Thread(target=self.brickDown, args=())
self.downThread.start()
#监听键盘事件
self.root.bind("<KeyPress>", self.onKeyBoardEvent)
self.root.mainloop()
self.start = False
main = Main()