pyQt4實(shí)現(xiàn)俄羅斯方塊游戲
本文實(shí)例為大家分享了pyQt4實(shí)現(xiàn)俄羅斯方塊游戲的具體代碼,供大家參考,具體內(nèi)容如下
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys, random
from PyQt4 import QtCore, QtGui
class Tetris(QtGui.QMainWindow):
#Tetris的構(gòu)造函數(shù),由于是QMainWindow的子類,所以要先調(diào)用父類的構(gòu)造函數(shù)
def __init__(self):
super(Tetris, self).__init__()
#QtGui.QMainWindow.__init__(self)
self.initUI()
def initUI(self):
self.tboard = Board(self) #創(chuàng)建一個(gè)Board類的實(shí)例
self.setCentralWidget(self.tboard) #將游戲窗口放到屏幕的中間
self.statusbar = self.statusBar() #創(chuàng)建狀態(tài)欄
self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage) #3種可能的信息:1.score 2.game over 3.pause
self.tboard.start() #開(kāi)始初始化程序
self.resize(180, 380) #游戲窗口的大小
#self.resize(480, 380) #游戲窗口的大小
self.center()
self.setWindowTitle('Tetris') #窗口的名字
self.show() #這句一定不能忘了,顯示窗口
def center(self):
#將游戲窗口放到屏幕的中間
screen = QtGui.QDesktopWidget().screenGeometry()
size = self.geometry()
self.move((screen.width()-size.width())/2,
(screen.height()-size.height())/2)
class Board(QtGui.QFrame):
msg2Statusbar = QtCore.pyqtSignal(str)
#游戲窗口的寬和高(單位為塊)
BoardWidth = 10 #寬度為10塊
BoardHeight = 22 #高度為22塊
Speed = 300 #游戲的速度
def __init__(self, parent):
super(Board, self).__init__(parent)
self.initBoard()
def initBoard(self):
'''''
初始化一些關(guān)鍵的變量
'''
self.timer = QtCore.QBasicTimer() #創(chuàng)建一個(gè)定時(shí)器
self.isWaitingAfterLine = False
self.curX = 0
self.curY = 0
self.numLinesRemoved = 0
#a list of numbers from 0-7.
#It represents the position of various shapes and remains of the shapes on the board.
self.board = []
self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.isStarted = False
self.isPaused = False
self.clearBoard()
#determine the type of a shape at a given block.
#返回(x,y)坐標(biāo)處對(duì)應(yīng)的點(diǎn)的類型
def shapeAt(self, x, y):
return self.board[(y * Board.BoardWidth) + x]
#設(shè)置(x,y)坐標(biāo)處對(duì)應(yīng)的點(diǎn)的類型
def setShapeAt(self, x, y, shape):
self.board[(y * Board.BoardWidth) + x] = shape
#calculate the width of the single square in pixels and return it
#The Board.BoardWidth is the size of the board in blocks
def squareWidth(self):
return self.contentsRect().width() / Board.BoardWidth
def squareHeight(self):
return self.contentsRect().height() / Board.BoardHeight
def start(self):
if self.isPaused: #如果暫停,直接返回
return
self.isStarted = True
self.isWaitingAfterLine = False
self.numLinesRemoved = 0
self.clearBoard()
self.msg2Statusbar.emit(str(self.numLinesRemoved))
self.newPiece()
self.timer.start(Board.Speed, self)
def pause(self):
if not self.isStarted:
return
self.isPaused = not self.isPaused
if self.isPaused:
self.timer.stop()
self.msg2Statusbar.emit("paused")
else:
self.timer.start(Board.Speed, self)
self.msg2Statusbar.emit(str(self.numLinesRemoved))
self.update()
def paintEvent(self, event):
painter = QtGui.QPainter(self)
rect = self.contentsRect()
boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight()
for i in range(Board.BoardHeight):
for j in range(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())
#按鍵相應(yīng)函數(shù)
def keyPressEvent(self, event):
#如果游戲沒(méi)有開(kāi)始(暫停)或者curPiece為空(游戲結(jié)束),響應(yīng)父窗口的按鍵事件,返回
if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape:
super(Board, self).keyPressEvent(event)
return
key = event.key() #捕獲按鍵
if key == QtCore.Qt.Key_P: #如果按鍵為P,暫?;蛘咧匦吕^續(xù)
self.pause()
return
if self.isPaused: #暫停時(shí)不響應(yīng)按鍵
return
elif key == QtCore.Qt.Key_Left: #如果按下了左箭頭會(huì)嘗試向左移動(dòng)(也有可能移動(dòng)不了)
self.tryMove(self.curPiece, self.curX - 1, self.curY)
elif key == QtCore.Qt.Key_Right:
self.tryMove(self.curPiece, self.curX + 1, self.curY)
elif key == QtCore.Qt.Key_Down: #按下下箭頭,向右旋轉(zhuǎn)
self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY)
elif key == QtCore.Qt.Key_Up: #按下上箭頭,向左旋轉(zhuǎn)
self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)
elif key == QtCore.Qt.Key_Space: #按下空格鍵,直接掉到底部
self.dropDown()
elif key == QtCore.Qt.Key_D:
self.oneLineDown()
else:
super(Board, self).keyPressEvent(event)
def timerEvent(self, event):
'''''
we either create a new piece, after the previous one was dropped to the bottom,
or we move a falling piece one line down.
'''
if event.timerId() == self.timer.timerId():
if self.isWaitingAfterLine:
self.isWaitingAfterLine = False
self.newPiece()
else:
self.oneLineDown()
else:
super(Board, self).timerEvent(event)
def clearBoard(self):
# 清除board,全部設(shè)置為NoShape
for i in range(Board.BoardHeight * Board.BoardWidth):
self.board.append(Tetrominoe.NoShape)
def dropDown(self):
newY = self.curY
while newY > 0:
#使curPiece一直沿著y減小的方向移動(dòng),直到不能移動(dòng)或者到達(dá)底部為止
if not self.tryMove(self.curPiece, self.curX, newY - 1):
break
newY -= 1 #自減1
self.pieceDropped()
def oneLineDown(self):
if not self.tryMove(self.curPiece, self.curX, self.curY - 1):
self.pieceDropped()
#到達(dá)底部的時(shí)候
def pieceDropped(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 not self.isWaitingAfterLine: #如果不是在暫停,開(kāi)始新的塊
self.newPiece()
def removeFullLines(self):
'''''
If the piece hits the bottom, we call the removeFullLines() method.
We find out all full lines and remove them.
We do it by moving all lines above the current full line to be removed one line down.
Notice that we reverse the order of the lines to be removed.
Otherwise, it would not work correctly.
In our case we use a naive gravity. This means, that the pieces may be floating above empty gaps.
'''
numFullLines = 0
rowsToRemove = []
for i in range(Board.BoardHeight):
n = 0 #n記錄每行shape的個(gè)數(shù)
for j in range(Board.BoardWidth):
if not self.shapeAt(j, i) == Tetrominoe.NoShape:
n = n + 1
#如果n等于10,將行號(hào)加入要?jiǎng)h除的隊(duì)列
if n == 10:
rowsToRemove.append(i)
rowsToRemove.reverse() #行號(hào)隊(duì)列反置
for m in rowsToRemove:
#從m行以上的shape均下移一行
for k in range(m, Board.BoardHeight):
for l in range(Board.BoardWidth):
self.setShapeAt(l, k, self.shapeAt(l, k + 1))
numFullLines = numFullLines + len(rowsToRemove) #統(tǒng)計(jì)消除的行數(shù)
if numFullLines > 0:
self.numLinesRemoved = self.numLinesRemoved + numFullLines
self.msg2Statusbar.emit(str(self.numLinesRemoved))
self.isWaitingAfterLine = True
self.curPiece.setShape(Tetrominoe.NoShape)
self.update()
def newPiece(self):
'''''
The newPiece() method creates randomly a new tetris piece.
If the piece cannot go into its initial position, the game is over.
隨機(jī)地創(chuàng)建一個(gè)方塊。如果方塊不能在它起始的位置,游戲結(jié)束。
'''
self.curPiece = Shape() #當(dāng)前塊
self.curPiece.setRandomShape() #隨機(jī)設(shè)置
self.curX = Board.BoardWidth / 2 + 1 #current X位置在中心
self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
#將self.curPiece移動(dòng)到當(dāng)前的坐標(biāo)處,如果不能移動(dòng),游戲結(jié)束。
#curPiece置為空,timer停止,顯示消息'game over'
if not self.tryMove(self.curPiece, self.curX, self.curY):
self.curPiece.setShape(Tetrominoe.NoShape)
self.timer.stop()
self.isStarted = False
self.msg2Statusbar.emit("Game over")
def tryMove(self, newPiece, newX, newY):
'''''
如果the shape is at the edge of the board 或者 is adjacent to some other piece, 返回False
否則的話,變動(dòng)位置并返回True
'''
for i in range(4):
x = newX + newPiece.x(i)
y = newY - newPiece.y(i)
'''''
如果x<0說(shuō)明已經(jīng)到了左邊緣;如果x>=Board.BoardWidth,說(shuō)明已經(jīng)到了右邊緣
如果y<0說(shuō)明已經(jīng)到了底部;如果x>=Board.BoardHeight,說(shuō)明已經(jīng)到了最頂部
以上情況均不能移動(dòng),返回False
'''
if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
return False
#如果當(dāng)前的位置不為空,返回False
if self.shapeAt(x, y) != Tetrominoe.NoShape:
return False
self.curPiece = newPiece
self.curX = newX #現(xiàn)在的坐標(biāo)變?yōu)樾伦鴺?biāo)
self.curY = newY
self.update() #frame更新
return True
def drawSquare(self, painter, x, y, shape):
colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC,
0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00]
color = QtGui.QColor(colorTable[shape])
painter.fillRect(x + 1, y + 1, self.squareWidth() - 2,
self.squareHeight() - 2, color)
painter.setPen(color.light())
painter.drawLine(x, y + self.squareHeight() - 1, x, y)
painter.drawLine(x, y, x + self.squareWidth() - 1, y)
painter.setPen(color.dark())
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)
class Tetrominoe(object):
'''''
定義游戲中出現(xiàn)的形狀,共有8種,分別用0-7表示。
其中0表示沒(méi)有形狀,1-7表示可能出現(xiàn)的形狀:Z,S,Line,T,Square,L,MirroredL。
相當(dāng)于C++中的枚舉類型,用有意義的字符串名代替數(shù)字
'''
NoShape = 0
ZShape = 1
SShape = 2
LineShape = 3
TShape = 4
SquareShape = 5
LShape = 6
MirroredLShape = 7
class Shape(object):
'''''
Shape類保存每種方塊的信息
'''
#coordsTable tuple holds all possible coordinate values of our Tetris pieces. 0-7
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)] #[[0, 0], [0, 0], [0, 0], [0, 0]]
self.pieceShape = Tetrominoe.NoShape
self.setShape(Tetrominoe.NoShape)
#返回當(dāng)前shape類型
def shape(self):
return self.pieceShape
def setShape(self, shape):
table = Shape.coordsTable[shape] #table是對(duì)應(yīng)的tuple元組
#將對(duì)應(yīng)的table賦給self.coords
for i in range(4):
for j in range(2):
self.coords[i][j] = table[i][j]
self.pieceShape = shape
#隨機(jī)獲取一個(gè)塊形狀(從1,2,3,4,5,6,7中隨機(jī)選1個(gè))
def setRandomShape(self):
self.setShape(random.randint(1, 7))
#返回index的x坐標(biāo),index是從0-3,分別表示方塊對(duì)應(yīng)的4個(gè)點(diǎn)
def x(self, index):
return self.coords[index][0]
#返回index的y坐標(biāo)
def y(self, index):
return self.coords[index][1]
#設(shè)置當(dāng)前index的x坐標(biāo)
def setX(self, index, x):
self.coords[index][0] = x
#設(shè)置當(dāng)前index的y坐標(biāo)
def setY(self, index, y):
self.coords[index][1] = y
#返回當(dāng)前塊的最小x坐標(biāo)
def minX(self):
m = self.coords[0][0]
for i in range(4):
m = min(m, self.coords[i][0])
return m
#返回當(dāng)前塊的最大x坐標(biāo)
def maxX(self):
m = self.coords[0][0]
for i in range(4):
m = max(m, self.coords[i][0])
return m
#返回當(dāng)前塊的最小y坐標(biāo)
def minY(self):
m = self.coords[0][1]
for i in range(4):
m = min(m, self.coords[i][1])
return m
#返回當(dāng)前塊的最大y坐標(biāo)
def maxY(self):
m = self.coords[0][1]
for i in range(4):
m = max(m, self.coords[i][1])
return m
def rotateLeft(self): #rotate a piece to the left
#如果塊是方塊的話,直接返回當(dāng)前塊,不做任何處理
if self.pieceShape == Tetrominoe.SquareShape:
return self
result = Shape()
result.pieceShape = self.pieceShape
for i in range(4):
#將i點(diǎn)的x坐標(biāo)換為y坐標(biāo)
result.setX(i, self.y(i))
#將i點(diǎn)的y坐標(biāo)換為-x坐標(biāo)
result.setY(i, -self.x(i))
#返回新的左旋后的方塊
return result
def rotateRight(self):
#如果塊是方塊的話,直接返回當(dāng)前塊,不做任何處理
if self.pieceShape == Tetrominoe.SquareShape:
return self
result = Shape()
result.pieceShape = self.pieceShape
for i in range(4):
#將i點(diǎn)的x坐標(biāo)換為-y坐標(biāo)
result.setX(i, -self.y(i))
#將i點(diǎn)的y坐標(biāo)換為x坐標(biāo)
result.setY(i, self.x(i))
#返回新的右旋后的方塊
return result
'''''
The game is simplified a bit so that it is easier to understand.
The game starts immediately after it is launched.
We can pause the game by pressing the p key.
The space key will drop the Tetris piece instantly to the bottom.
The game goes at constant speed, no acceleration is implemented.
The score is the number of lines that we have removed.
'''
def main():
#創(chuàng)建一個(gè)界面app
app = QtGui.QApplication([])
#創(chuàng)建一個(gè)俄羅斯方塊類
tetris = Tetris()
#進(jìn)入主循環(huán)
app.exec_()
if __name__ == '__main__':
main()
源代碼來(lái)自:詳細(xì)鏈接
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇3)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇2)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇1)
- pyqt5實(shí)現(xiàn)俄羅斯方塊游戲
- Python小游戲之300行代碼實(shí)現(xiàn)俄羅斯方塊
- python實(shí)現(xiàn)俄羅斯方塊游戲
- python實(shí)現(xiàn)俄羅斯方塊
- pygame實(shí)現(xiàn)俄羅斯方塊游戲
- python和pygame實(shí)現(xiàn)簡(jiǎn)單俄羅斯方塊游戲
- Python使用pygame模塊編寫(xiě)俄羅斯方塊游戲的代碼實(shí)例
- 用Python編寫(xiě)一個(gè)簡(jiǎn)單的俄羅斯方塊游戲的教程
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(AI篇1)
相關(guān)文章
如何使用Python實(shí)現(xiàn)CartPole游戲
在深度強(qiáng)化學(xué)習(xí)內(nèi)容的介紹中,提出了CartPole游戲進(jìn)行深度強(qiáng)化學(xué)習(xí),現(xiàn)在提供一種用Python簡(jiǎn)單實(shí)現(xiàn)Cart Pole游戲的方法,感興趣的朋友跟隨小編一起看看吧2024-07-07
利用Python腳本實(shí)現(xiàn)ping百度和google的方法
最近在做SEO的時(shí)候,為了讓發(fā)的外鏈能夠快速的收錄,想到了利用ping的功能,google和百度都有相關(guān)的ping介紹,有興趣的朋友可以去看看相關(guān)的知識(shí)。下面這篇文章主要介紹了利用Python腳本實(shí)現(xiàn)ping百度和google的方法,需要的朋友可以參考借鑒,一起來(lái)看看吧。2017-01-01
Python基礎(chǔ)之?dāng)?shù)據(jù)類型相關(guān)知識(shí)總結(jié)
眾所周知,在Python中,常用的數(shù)據(jù)類型有三種,分別是字符串、整數(shù)和浮點(diǎn)數(shù).在Python基礎(chǔ)學(xué)習(xí)的過(guò)程中,數(shù)據(jù)類型是初學(xué)者常常容易混淆的一個(gè)基礎(chǔ)知識(shí)點(diǎn),本文為大家詳細(xì)總結(jié)了三種數(shù)據(jù)類型的概念、數(shù)據(jù)類型的查詢以及更為復(fù)雜的數(shù)據(jù)轉(zhuǎn)化,需要的朋友可以參考下2021-06-06
pandas 按日期范圍篩選數(shù)據(jù)的實(shí)現(xiàn)
這篇文章主要介紹了pandas 按日期范圍篩選數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
Python定義二叉樹(shù)及4種遍歷方法實(shí)例詳解
這篇文章主要介紹了Python定義二叉樹(shù)及4種遍歷方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了二叉樹(shù)的概念、原理,以及Python定義與遍歷二叉樹(shù)相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
python實(shí)現(xiàn)合并多個(gè)list及合并多個(gè)django QuerySet的方法示例
這篇文章主要介紹了python實(shí)現(xiàn)合并多個(gè)list及合并多個(gè)django QuerySet的方法,結(jié)合實(shí)例形式分析了Python使用chain合并多個(gè)list以及合并Django中多個(gè)QuerySet的相關(guān)操作技巧,需要的朋友可以參考下2019-06-06
python?logging多進(jìn)程多線程輸出到同一個(gè)日志文件的實(shí)戰(zhàn)案例
這篇文章主要介紹了python?logging多進(jìn)程多線程輸出到同一個(gè)日志文件的實(shí)戰(zhàn)案例,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02

