PyQt5製作俄羅斯方塊的思路
阿新 • • 發佈:2022-03-14
近來閒來無事在學習PyQt5,再看文件看到最後的俄羅斯方塊的時候百思不得其解,把程式跑起來也看不到效果因為看不到圖形,所以我就自己想做一個,以下是我要分享的思路。
一、先分析以下俄羅斯方塊是要在介面上顯示方塊所以首先我們要先畫方塊,我就找了劃方塊的例子,來自PyQt5中文教程中的繪圖章節。
1 from PyQt5.QtWidgets import QWidget,QApplication 2 from PyQt5.QtGui import QPainter,QColor,QBrush 3 import sys 4 5 class Example(QWidget):View Code6 def __init__(self): 7 super(Example, self).__init__() 8 self.initUI() 9 10 def initUI(self): 11 self.setGeometry(300,300,350,100) 12 self.setWindowTitle('Colors') 13 self.show() 14 15 def paintEvent(self, e): 16 qp = QPainter() 17 qp.begin(self)18 self.drawRectangles(qp) 19 qp.end() 20 21 def drawRectangles(self,qp): 22 col = QColor(0,0,0) 23 col.setNamedColor('#d4d4d4') 24 qp.setPen(col) 25 qp.setBrush(QColor(200,0,0)) 26 qp.drawRect(10,15,90,60) 27 qp.setBrush(QColor(255,80,0,160)) 28qp.drawRect(130,15,90,60) 29 qp.setBrush(QColor(25,0,90,200)) 30 qp.drawRect(250,15,90,60) 31 32 if __name__ == '__main__': 33 app = QApplication(sys.argv) 34 ex = Example() 35 sys.exit(app.exec_())
這個例子是叫我們畫矩形,之後照著書上俄羅斯方塊的思路,是將圖形定義在列表裡面,裡面存了座標點。
1 class Shape(object): 2 coordsTable = (((0, -1), (0, 0), 3 (-1, 0), (-1, 1)), 4 5 ((0, -1), (0, 0), 6 (1, 0), (1, 1)), 7 8 ((0, -1), (0, 0), 9 (0, 1), (0, 2)), 10 11 ((-1, 0), (0, 0), 12 (1, 0), (0, 1)), 13 14 ((0, 0), (1, 0), 15 (0, 1), (1, 1)), 16 17 ((-1, -1), (0, -1), 18 (0, 0), (0, 1)), 19 20 ((1, -1), (0, -1), 21 (0, 0), (0, 1))) 22 23 def __init__(self): 24 self.coords = [[0,0] for i in range(4)] 25 self.setRandomShape() 26 27 def shape(self): 28 return self.pieceShape 29 30 def setShape(self, shape): 31 table = Shape.coordsTable[shape] 32 for i in range(4): 33 for j in range(2): 34 self.coords[i][j] = table[i][j] 35 self.pieceShape = shape 36 37 def setRandomShape(self): 38 self.setShape(random.randint(1, 6))View Code
這個書上的解釋,我也是按照這個方法定義的方塊,接下來我來說我的做法,這裡涉及到一點演算法,用這個座標想要在自己定義的介面上顯示20*20的方塊必須讓他的橫座標減去0.5再乘以20,讓他的縱座標加上0.5在乘以20,這樣就可以使用畫矩形的方法QPaint.drawRect()畫出20*20的方塊,程式碼如下:
1 def drawRectangles(self,qp): 2 col = QColor(0,0,0) 3 col.setNamedColor('#d4d4d4') 4 qp.setPen(col) 5 qp.setBrush(QColor(200,0,0)) 6 for i in self.shape.coords: 7 qp.drawRect(self.Vline*20+(i[0]-0.5)*20,self.Hline*20+(i[1]+0.5)*20,20,20)View Code
這樣就能畫出方塊了,但是想要方塊隨機發生變化,書上的程式碼裡已經寫了setRandomShape(self)函式,只需要再將類中的self.coords拿出來就可以拿到要展示的方塊,那就應該把注意力放在變化上,這個需要使用到QBasicTimer類,然後寫timerevent,來讓方塊動起來。
1 self.Speed = 1000 2 self.timer = QBasicTimer() 3 self.timer.start(self.Speed,self) 4 5 def timerEvent(self,event): 6 self.shape.setRandomShape() 7 self.update()View Code
這樣方塊就可以隨機的出現在介面上,接下來就是下掉,這裡我做了格子,因為我的方塊是20*20的,介面是600*800的,所以左右有30列,上下有40行,所以方塊出現的位置的計算方法應該是行數乘以20加上方塊的顯示的畫素數
qp.drawRect(self.Vline*20+(i[0]-0.5)*20,self.Hline*20+(i[1]+0.5)*20,20,20)
,我將行列定義為全域性變數,通過控制全域性變數來控制左右,以及下掉。程式碼如下:
1 from PyQt5.QtWidgets import QWidget,QApplication,QDesktopWidget 2 from PyQt5.QtGui import QPainter,QColor,QBrush 3 from PyQt5.QtCore import QBasicTimer,Qt 4 import sys,random 5 6 class Example(QWidget): 7 def __init__(self): 8 super(Example, self).__init__() 9 self.initUI() 10 11 def initUI(self): 12 self.Hline = 1 13 self.Vline =15 14 self.Speed = 1000 15 self.newPiece = False 16 self.pause = False 17 self.shape = Shape() 18 self.setGeometry(300,300,600,800) 19 screen = QDesktopWidget().screenGeometry() 20 size = self.geometry() 21 self.move(int((screen.width()-size.width())/2),int((screen.height()-size.height())/2)) 22 self.setWindowTitle('Colors') 23 self.show() 24 self.timer = QBasicTimer() 25 self.timer.start(self.Speed,self) 26 27 28 def keyPressEvent(self, event): 29 key = event.key() 30 if key == Qt.Key_P: 31 if self.pause: 32 self.timer.stop() 33 else: 34 self.timer.start(self.Speed,self) 35 elif key == Qt.Key_Left: 36 if self.Vline > 0: 37 self.Vline = self.Vline - 1 38 elif key == Qt.Key_Right: 39 if self.Vline < 29: 40 self.Vline = self.Vline + 1 41 elif key == Qt.Key_Down: 42 self.Speed = 100 43 elif key == Qt.Key_Up: 44 self.Speed = 100 45 elif key == Qt.Key_Space: 46 self.Speed = 10 47 self.timer.stop() 48 self.timer.start(self.Speed,self) 49 elif key == Qt.Key_D: 50 self.Speed = 100 51 else: 52 super(Example, self).keyPressEvent(event) 53 54 def paintEvent(self, e): 55 qp = QPainter() 56 qp.begin(self) 57 self.drawRectangles(qp) 58 qp.end() 59 60 def timerEvent(self,event): 61 self.Hline = self.Hline + 1 62 self.downCollisionDetection() 63 if self.newPiece: 64 self.shape.setRandomShape() 65 self.newPiece = False 66 self.Hline = 1 67 self.Vline = 15 68 self.update() 69 # if event.timerId() == self.timer.timerId(): 70 # if self.isWaitingAfterLine: 71 # self.isWaitingAfterLine = False 72 # self.newPiece() 73 # else: 74 # self.oneLineDown() 75 # else: 76 # super(Board,self).timerEvent(event) 77 78 def drawRectangles(self,qp): 79 col = QColor(0,0,0) 80 col.setNamedColor('#d4d4d4') 81 qp.setPen(col) 82 qp.setBrush(QColor(200,0,0)) 83 for i in self.shape.coords: 84 qp.drawRect(self.Vline*20+(i[0]-0.5)*20,self.Hline*20+(i[1]+0.5)*20,20,20) 85 # qp.setBrush(QColor(255,80,0,160)) 86 # qp.drawRect(130,15,90,60) 87 # qp.setBrush(QColor(25,0,90,200)) 88 # qp.drawRect(250,15,90,60) 89 90 def downCollisionDetection(self): 91 if self.Hline > 39: 92 self.newPiece = True 93 94 95 96 class Tetrominoe(object): 97 ZShape = 1 98 SShape = 2 99 LineShape = 3 100 TShape = 4 101 SquareShape = 5 102 LShape = 6 103 MirroredLShape = 7 104 class Shape(object): 105 coordsTable = (((0, -1), (0, 0), 106 (-1, 0), (-1, 1)), 107 108 ((0, -1), (0, 0), 109 (1, 0), (1, 1)), 110 111 ((0, -1), (0, 0), 112 (0, 1), (0, 2)), 113 114 ((-1, 0), (0, 0), 115 (1, 0), (0, 1)), 116 117 ((0, 0), (1, 0), 118 (0, 1), (1, 1)), 119 120 ((-1, -1), (0, -1), 121 (0, 0), (0, 1)), 122 123 ((1, -1), (0, -1), 124 (0, 0), (0, 1))) 125 126 def __init__(self): 127 self.coords = [[0,0] for i in range(4)] 128 self.setRandomShape() 129 130 def shape(self): 131 return self.pieceShape 132 133 def setShape(self, shape): 134 table = Shape.coordsTable[shape] 135 for i in range(4): 136 for j in range(2): 137 self.coords[i][j] = table[i][j] 138 self.pieceShape = shape 139 140 def setRandomShape(self): 141 self.setShape(random.randint(1, 6)) 142 143 def x(self, index): 144 return self.coords[index][0] 145 146 def y(self, index): 147 return self.coords[index][1] 148 149 def setX(self, index, x): 150 self.coords[index][0] = x 151 152 def setY(self, index, y): 153 self.coords[index][1] = y 154 155 def minX(self): 156 m = self.coords[0][0] 157 for i in range(4): 158 m = min(m, self.coords[i][0]) 159 return m 160 161 def maxX(self): 162 m = self.coords[0][0] 163 for i in range(4): 164 m = max(m, self.coords[i][0]) 165 return m 166 167 def minY(self): 168 m = self.coords[0][1] 169 for i in range(4): 170 m = min(m, self.coords[i][1]) 171 return m 172 173 def maxY(self): 174 m = self.coords[0][1] 175 for i in range(4): 176 m = max(m, self.coords[i][1]) 177 return m 178 179 def rotateLeft(self): 180 if self.pieceShape == Tetrominoe.SquareShape: 181 return self 182 result = Shape() 183 result.pieceShape = self.pieceShape 184 for i in range(4): 185 result.setX(i, self.y(i)) 186 result.setY(i, -self.x(i)) 187 return result 188 189 def rotateRight(self): 190 if self.pieceShape == Tetrominoe.SquareShape: 191 return self 192 result = Shape() 193 result.pieceShape = self.pieceShape 194 for i in range(4): 195 result.setX(i, -self.y(i)) 196 result.setY(i, self.x(i)) 197 return result 198 199 if __name__ == '__main__': 200 app = QApplication(sys.argv) 201 ex = Example() 202 sys.exit(app.exec_())View Code
做到這裡的效果展示:
二、接下來我們就要將方塊在介面上停下來,不過我還沒做,欲聽後事如何,請聽下回分解。。。。