python俄罗斯方块代码34行_Python_俄罗斯方块

"""俄罗斯方块

author: wolfstar

last edited: 2018年1月"""

importsys, randomfrom PyQt5.QtWidgets importQMainWindow, QFrame, QDesktopWidget, QApplicationfrom PyQt5.QtCore importQt, QBasicTimer, pyqtSignalfrom PyQt5.QtGui importQPainter, QColor#主界面类

classTetris(QMainWindow):def __init__(self):

super().__init__()

self.initUI()definitUI(self):#Board创建一个面板类的实例,并设置应用程序的核心部件。

self.tboard =Board(self)

self.setCentralWidget(self.tboard)#创建一个状态栏将显示消息。我们将显示三种可能的消息:已删除的行数,停顿了一下消息,或游戏结束的消息。msg2Statusbar是一个自定义的信号,在Board 中实现类。showMessage()是一个内置的方法,在状态栏显示一条消息。

self.statusbar =self.statusBar()

self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)#这一行代码启动游戏

self.tboard.start()

self.resize(180, 380)

self.center()

self.setWindowTitle('Tetris')

self.show()#窗体居中显示方法

defcenter(self):

screen=QDesktopWidget().screenGeometry()

size=self.geometry()

self.move((screen.width()- size.width()) / 2,

(screen.height()- size.height()) / 2)#创建面板类

classBoard(QFrame):#创建一个自定义的信号。当我们想写一个信息或状态栏的分数的时候,msg2Statusbar发出一个信号

msg2Statusbar =pyqtSignal(str)#这些都是Board的类变量。BoardWidth和BoardHeight定义的块的大小。Speed定义了游戏的速度。每个300 ms将开始一个新游戏循环。

BoardWidth = 10BoardHeight= 22Speed= 300

def __init__(self, parent):

super().__init__(parent)

self.initBoard()#我们在initBoard()方法初始化一些重要的变量。board变量是一个从0到7的数字列表。它代表了面板上各种形状和位置。

definitBoard(self):

self.timer=QBasicTimer()

self.isWaitingAfterLine=False

self.curX=0

self.curY=0

self.numLinesRemoved=0

self.board=[]

self.setFocusPolicy(Qt.StrongFocus)

self.isStarted=False

self.isPaused=False

self.clearBoard()#shapeAt()方法确定在给定形状块的类型。

defshapeAt(self, x, y):return self.board[(y * Board.BoardWidth) +x]defsetShapeAt(self, x, y, shape):

self.board[(y* Board.BoardWidth) + x] =shape#Board可以动态地调整大小。因此,块的大小可能会有所改变。squareWidth()计算单一方块像素的宽度并返回它。Board.BoardWidth方块板的大小。

defsquareWidth(self):return self.contentsRect().width() //Board.BoardWidthdefsquareHeight(self):return self.contentsRect().height() //Board.BoardHeight#游戏开始方法

defstart(self):ifself.isPaused:returnself.isStarted=True

self.isWaitingAfterLine=False

self.numLinesRemoved=0

self.clearBoard()

self.msg2Statusbar.emit(str(self.numLinesRemoved))

self.newPiece()

self.timer.start(Board.Speed, self)#游戏暂停方法

defpause(self):if notself.isStarted:returnself.isPaused= notself.isPausedifself.isPaused:

self.timer.stop()

self.msg2Statusbar.emit("paused")else:

self.timer.start(Board.Speed, self)

self.msg2Statusbar.emit(str(self.numLinesRemoved))

self.update()#窗体绘图

defpaintEvent(self, event):

painter=QPainter(self)#根据窗体舞台大小计算顶部

rect =self.contentsRect()

boardTop= rect.bottom() - Board.BoardHeight *self.squareHeight()#游戏的绘制分为两个步骤,第一步,绘制所有方块,这些方块都要保存在底部列表中。列表通过shapeAt() 方法来添加方块。

for i inrange(Board.BoardHeight):for j inrange(Board.BoardWidth):

shape= self.shapeAt(j, Board.BoardHeight - i - 1)if shape !=Tetrominoe.NoShape:

self.drawSquare(painter,

rect.left()+ j *self.squareWidth(),

boardTop+ i *self.squareHeight(), shape)#第二步绘制下降中的方块

if self.curPiece.shape() !=Tetrominoe.NoShape:for i in range(4):

x= self.curX +self.curPiece.x(i)

y= self.curY -self.curPiece.y(i)

self.drawSquare(painter, rect.left()+ x *self.squareWidth(),

boardTop+ (Board.BoardHeight - y - 1) *self.squareHeight(),

self.curPiece.shape())defkeyPressEvent(self, event):if not self.isStarted or self.curPiece.shape() ==Tetrominoe.NoShape:

super(Board, self).keyPressEvent(event)returnkey=event.key()if key ==Qt.Key_P:

self.pause()return

ifself.isPaused:return

#keyPressEvent()方法检查按下键。当按右箭头键,我们试图向右移动一块。我们使用tyrMove,因为可能无法移动。

elif key ==Qt.Key_Left:

self.tryMove(self.curPiece, self.curX- 1, self.curY)elif key ==Qt.Key_Right:

self.tryMove(self.curPiece, self.curX+ 1, self.curY)#向上箭头键将旋转方块。

elif key ==Qt.Key_Down:

self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)elif key ==Qt.Key_Up:

self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)#空格键立即下降到底部

elif key ==Qt.Key_Space:

self.dropDown()#按下D键,可以加速下降。

elif key ==Qt.Key_D:

self.oneLineDown()else:

super(Board, self).keyPressEvent(event)#计时器事件,当我们前一个方块降到底部后,创建一个新的方块。

deftimerEvent(self, event):if event.timerId() ==self.timer.timerId():ifself.isWaitingAfterLine:

self.isWaitingAfterLine=False

self.newPiece()else:

self.oneLineDown()else:

super(Board, self).timerEvent(event)#clearBoard()方法通过设置Tetrominoe.NoShape清除面板

defclearBoard(self):for i in range(Board.BoardHeight *Board.BoardWidth):

self.board.append(Tetrominoe.NoShape)defdropDown(self):

newY=self.curYwhile newY >0:if not self.tryMove(self.curPiece, self.curX, newY - 1):breaknewY-= 1self.pieceDropped()defoneLineDown(self):if not self.tryMove(self.curPiece, self.curX, self.curY - 1):

self.pieceDropped()defpieceDropped(self):for i in range(4):

x= self.curX +self.curPiece.x(i)

y= self.curY -self.curPiece.y(i)

self.setShapeAt(x, y, self.curPiece.shape())

self.removeFullLines()if notself.isWaitingAfterLine:

self.newPiece()#如果到达底部,会调用removeFullLines()方法。我们会检查所有完整的线条然后删除它们。然后移动所有行高于当前删除整行一行。请注意,我们反的顺序行被删除。否则,就会出错。

defremoveFullLines(self):

numFullLines=0

rowsToRemove=[]for i inrange(Board.BoardHeight):

n=0for j inrange(Board.BoardWidth):if not self.shapeAt(j, i) ==Tetrominoe.NoShape:

n= n + 1

if n == 10:

rowsToRemove.append(i)

rowsToRemove.reverse()for m inrowsToRemove:for k inrange(m, Board.BoardHeight):for l inrange(Board.BoardWidth):

self.setShapeAt(l, k, self.shapeAt(l, k+ 1))

numFullLines= numFullLines +len(rowsToRemove)if numFullLines >0:

self.numLinesRemoved= self.numLinesRemoved +numFullLines

self.msg2Statusbar.emit(str(self.numLinesRemoved))

self.isWaitingAfterLine=True

self.curPiece.setShape(Tetrominoe.NoShape)

self.update()#通过newPiece()方法创建一个新的方块,如果不能进入它的初始位置,游戏就结束了。

defnewPiece(self):

self.curPiece=Shape()

self.curPiece.setRandomShape()

self.curX= Board.BoardWidth // 2 + 1self.curY= Board.BoardHeight - 1 +self.curPiece.minY()if notself.tryMove(self.curPiece, self.curX, self.curY):

self.curPiece.setShape(Tetrominoe.NoShape)

self.timer.stop()

self.isStarted=False

self.msg2Statusbar.emit("Game over")#使用tryMove()方法尝试移动方块。如果方块的边缘已经接触到面板边缘或者不能移动,我们返回False。否则我们当前块下降到一个新的位置。

deftryMove(self, newPiece, newX, newY):for i in range(4):

x= newX +newPiece.x(i)

y= newY -newPiece.y(i)if x < 0 or x >= Board.BoardWidth or y < 0 or y >=Board.BoardHeight:returnFalseif self.shapeAt(x, y) !=Tetrominoe.NoShape:returnFalse

self.curPiece=newPiece

self.curX=newX

self.curY=newY

self.update()returnTruedefdrawSquare(self, painter, x, y, shape):

colorTable= [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]

color=QColor(colorTable[shape])

painter.fillRect(x+ 1, y + 1, self.squareWidth() - 2,

self.squareHeight()- 2, color)

painter.setPen(color.lighter())

painter.drawLine(x, y+ self.squareHeight() - 1, x, y)

painter.drawLine(x, y, x+ self.squareWidth() - 1, y)

painter.setPen(color.darker())

painter.drawLine(x+ 1, y + self.squareHeight() - 1,

x+ self.squareWidth() - 1, y + self.squareHeight() - 1)

painter.drawLine(x+ self.squareWidth() - 1,

y+ self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)#Tetrominoe类包含所有可能的形状。NoShape空形状。

classTetrominoe(object):

NoShape=0

ZShape= 1SShape= 2LineShape= 3TShape= 4SquareShape= 5LShape= 6MirroredLShape= 7

#Shape 类保存方块信息

classShape(object):#coordsTable 元组包含所有可能的俄罗斯方块的坐标值。这是一个模板的所有块坐标值。

coordsTable =(

((0, 0), (0, 0), (0, 0), (0, 0)),

((0,-1), (0, 0), (-1, 0), (-1, 1)),

((0,-1), (0, 0), (1, 0), (1, 1)),

((0,-1), (0, 0), (0, 1), (0, 2)),

((-1, 0), (0, 0), (1, 0), (0, 1)),

((0, 0), (1, 0), (0, 1), (1, 1)),

((-1, -1), (0, -1), (0, 0), (0, 1)),

((1, -1), (0, -1), (0, 0), (0, 1))

)def __init__(self):

self.coords= [[0, 0] for i in range(4)]

self.pieceShape=Tetrominoe.NoShape

self.setShape(Tetrominoe.NoShape)defshape(self):returnself.pieceShapedefsetShape(self, shape):

table=Shape.coordsTable[shape]for i in range(4):for j in range(2):

self.coords[i][j]=table[i][j]

self.pieceShape=shapedefsetRandomShape(self):

self.setShape(random.randint(1, 7))defx(self, index):returnself.coords[index][0]defy(self, index):return self.coords[index][1]defsetX(self, index, x):

self.coords[index][0]=xdefsetY(self, index, y):

self.coords[index][1] =ydefminX(self):

m=self.coords[0][0]for i in range(4):

m=min(m, self.coords[i][0])returnmdefmaxX(self):

m=self.coords[0][0]for i in range(4):

m=max(m, self.coords[i][0])returnmdefminY(self):

m= self.coords[0][1]for i in range(4):

m= min(m, self.coords[i][1])returnmdefmaxY(self):

m= self.coords[0][1]for i in range(4):

m= max(m, self.coords[i][1])returnm#rotateLeft() 向左旋转方块。如果方块本身不能被旋转,我们就返回当前对象的应用。否则就创建一个新的块及其坐标设置为的旋转。

defrotateLeft(self):if self.pieceShape ==Tetrominoe.SquareShape:returnself

result=Shape()

result.pieceShape=self.pieceShapefor i in range(4):

result.setX(i, self.y(i))

result.setY(i,-self.x(i))returnresultdefrotateRight(self):if self.pieceShape ==Tetrominoe.SquareShape:returnself

result=Shape()

result.pieceShape=self.pieceShapefor i in range(4):

result.setX(i,-self.y(i))

result.setY(i, self.x(i))returnresultif __name__ == '__main__':

app=QApplication([])

tetris=Tetris()

sys.exit(app.exec_())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值