1. 程式人生 > 其它 >PyQt5製作俄羅斯方塊的思路

PyQt5製作俄羅斯方塊的思路

         近來閒來無事在學習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):
6 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)) 28
qp.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_())
View Code

這個例子是叫我們畫矩形,之後照著書上俄羅斯方塊的思路,是將圖形定義在列表裡面,裡面存了座標點。

 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

做到這裡的效果展示:

 

二、接下來我們就要將方塊在介面上停下來,不過我還沒做,欲聽後事如何,請聽下回分解。。。。