|
1 function TetrixBoard(ui) |
|
2 { |
|
3 this.ui = ui; |
|
4 |
|
5 this.isStarted = false; |
|
6 this.isPaused = false; |
|
7 this.inKeyPress = false; |
|
8 |
|
9 this._board = new Array(TetrixBoard.BoardWidth * TetrixBoard.BoardHeight); |
|
10 this.clearBoard(); |
|
11 |
|
12 this.curPiece = new TetrixPiece(); |
|
13 this.nextPiece = new TetrixPiece(); |
|
14 this.nextPiece.setRandomShape(); |
|
15 |
|
16 ui.timer.singleShot = true; |
|
17 ui.timer.timeout.connect(this, this.onTimer); |
|
18 ui.keyPressed.connect(this, this.onKeyPress); |
|
19 ui.paintRequested.connect(this, this.onPaint); |
|
20 ui.paintNextPieceRequested.connect(this, this.onPaintNextPiece); |
|
21 } |
|
22 |
|
23 TetrixBoard.BoardWidth = 10; |
|
24 TetrixBoard.BoardHeight = 22; |
|
25 |
|
26 TetrixBoard.prototype.start = function() { |
|
27 if (this.isPaused) |
|
28 return; |
|
29 |
|
30 this.isStarted = true; |
|
31 this.isWaitingAfterLine = false; |
|
32 this.numLinesRemoved = 0; |
|
33 this.numPiecesDropped = 0; |
|
34 this.score = 0; |
|
35 this.level = 1; |
|
36 this.clearBoard(); |
|
37 |
|
38 this.ui.linesRemovedChanged(this.numLinesRemoved); |
|
39 this.ui.scoreChanged(this.score); |
|
40 this.ui.levelChanged(this.level); |
|
41 |
|
42 this.newPiece(); |
|
43 this.ui.timer.start(this.timeoutTime()); |
|
44 } |
|
45 |
|
46 TetrixBoard.prototype.pause = function() { |
|
47 if (!this.isStarted) |
|
48 return; |
|
49 |
|
50 this.isPaused = !this.isPaused; |
|
51 if (this.isPaused) { |
|
52 this.ui.timer.stop(); |
|
53 } else { |
|
54 this.ui.timer.start(this.timeoutTime()); |
|
55 } |
|
56 this.ui.update(); |
|
57 } |
|
58 |
|
59 TetrixBoard.prototype.getShapeAt = function(x, y) { |
|
60 return this._board[(y * TetrixBoard.BoardWidth) + x]; |
|
61 } |
|
62 |
|
63 TetrixBoard.prototype.setShapeAt = function(x, y, newShape) { |
|
64 this._board[(y * TetrixBoard.BoardWidth) + x] = newShape; |
|
65 } |
|
66 |
|
67 TetrixBoard.prototype.clearBoard = function() { |
|
68 for (var i = 0; i < TetrixBoard.BoardHeight * TetrixBoard.BoardWidth; ++i) |
|
69 this._board[i] = TetrixShape.NoShape; |
|
70 } |
|
71 |
|
72 TetrixBoard.prototype.dropDown = function() { |
|
73 var dropHeight = 0; |
|
74 var newY = this.curY; |
|
75 while (newY > 0) { |
|
76 if (!this.tryMove(this.curPiece, this.curX, newY - 1)) |
|
77 break; |
|
78 --newY; |
|
79 ++dropHeight; |
|
80 } |
|
81 this.pieceDropped(dropHeight); |
|
82 } |
|
83 |
|
84 TetrixBoard.prototype.oneLineDown = function() { |
|
85 if (!this.tryMove(this.curPiece, this.curX, this.curY - 1)) |
|
86 this.pieceDropped(0); |
|
87 } |
|
88 |
|
89 TetrixBoard.prototype.pieceDropped = function(dropHeight) { |
|
90 for (var i = 0; i < 4; ++i) { |
|
91 var x = this.curX + this.curPiece.getX(i); |
|
92 var y = this.curY - this.curPiece.getY(i); |
|
93 this.setShapeAt(x, y, this.curPiece.shape); |
|
94 } |
|
95 |
|
96 ++this.numPiecesDropped; |
|
97 if ((this.numPiecesDropped % 25) == 0) { |
|
98 ++this.level; |
|
99 this.ui.timer.start(this.timeoutTime()); |
|
100 this.ui.levelChanged(this.level); |
|
101 } |
|
102 |
|
103 this.score += dropHeight + 7; |
|
104 this.ui.scoreChanged(this.score); |
|
105 this.removeFullLines(); |
|
106 |
|
107 if (!this.isWaitingAfterLine) |
|
108 this.newPiece(); |
|
109 |
|
110 if (this.isStarted && !this.ui.timer.active) |
|
111 this.ui.timer.start(this.timeoutTime()); |
|
112 } |
|
113 |
|
114 TetrixBoard.prototype.removeFullLines = function() { |
|
115 var numFullLines = 0; |
|
116 |
|
117 for (var i = TetrixBoard.BoardHeight - 1; i >= 0; --i) { |
|
118 var lineIsFull = true; |
|
119 |
|
120 for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { |
|
121 if (this.getShapeAt(j, i) == TetrixShape.NoShape) { |
|
122 lineIsFull = false; |
|
123 break; |
|
124 } |
|
125 } |
|
126 |
|
127 if (lineIsFull) { |
|
128 ++numFullLines; |
|
129 for (var k = i; k < TetrixBoard.BoardHeight - 1; ++k) { |
|
130 for (var j = 0; j < TetrixBoard.BoardWidth; ++j) |
|
131 this.setShapeAt(j, k, this.getShapeAt(j, k + 1)); |
|
132 } |
|
133 for (var j = 0; j < TetrixBoard.BoardWidth; ++j) |
|
134 this.setShapeAt(j, TetrixBoard.BoardHeight - 1, TetrixShape.NoShape); |
|
135 } |
|
136 } |
|
137 |
|
138 if (numFullLines > 0) { |
|
139 this.numLinesRemoved += numFullLines; |
|
140 this.score += 10 * numFullLines; |
|
141 this.ui.linesRemovedChanged(this.numLinesRemoved); |
|
142 this.ui.scoreChanged(this.score); |
|
143 |
|
144 this.ui.timer.start(500); |
|
145 this.isWaitingAfterLine = true; |
|
146 this.curPiece.shape = TetrixShape.NoShape; |
|
147 this.ui.update(); |
|
148 } |
|
149 } |
|
150 |
|
151 TetrixBoard.prototype.newPiece = function() { |
|
152 this.curPiece = this.nextPiece; |
|
153 this.nextPiece = new TetrixPiece(); |
|
154 this.nextPiece.setRandomShape(); |
|
155 this.ui.showNextPiece(this.nextPiece.maxX - this.nextPiece.minX + 1, |
|
156 this.nextPiece.maxY - this.nextPiece.minY + 1); |
|
157 this.curX = TetrixBoard.BoardWidth / 2 + 1; |
|
158 this.curY = TetrixBoard.BoardHeight - 1 + this.curPiece.minY; |
|
159 |
|
160 if (!this.tryMove(this.curPiece, this.curX, this.curY)) { |
|
161 this.curPiece.shape = TetrixShape.NoShape; |
|
162 this.ui.timer.stop(); |
|
163 this.isStarted = false; |
|
164 } |
|
165 } |
|
166 |
|
167 TetrixBoard.prototype.tryMove = function(newPiece, newX, newY) { |
|
168 for (var i = 0; i < 4; ++i) { |
|
169 var x = newX + newPiece.getX(i); |
|
170 var y = newY - newPiece.getY(i); |
|
171 if ((x < 0) || (x >= TetrixBoard.BoardWidth) || (y < 0) || (y >= TetrixBoard.BoardHeight)) |
|
172 return false; |
|
173 if (this.getShapeAt(x, y) != TetrixShape.NoShape) |
|
174 return false; |
|
175 } |
|
176 |
|
177 this.curPiece = newPiece; |
|
178 this.curX = newX; |
|
179 this.curY = newY; |
|
180 this.ui.update(); |
|
181 return true; |
|
182 } |
|
183 |
|
184 TetrixBoard.prototype.onPaint = function(painter) { |
|
185 if (this.isPaused) { |
|
186 this.ui.drawPauseScreen(painter); |
|
187 return; |
|
188 } |
|
189 |
|
190 for (var i = 0; i < TetrixBoard.BoardHeight; ++i) { |
|
191 for (var j = 0; j < TetrixBoard.BoardWidth; ++j) { |
|
192 var shape = this.getShapeAt(j, TetrixBoard.BoardHeight - i - 1); |
|
193 if (shape != TetrixShape.NoShape) |
|
194 this.ui.drawSquare(painter, j, i, shape); |
|
195 } |
|
196 } |
|
197 |
|
198 if (this.curPiece.shape != TetrixShape.NoShape) { |
|
199 for (var i = 0; i < 4; ++i) { |
|
200 var x = this.curX + this.curPiece.getX(i); |
|
201 var y = this.curY - this.curPiece.getY(i); |
|
202 this.ui.drawSquare(painter, x, TetrixBoard.BoardHeight - y - 1, |
|
203 this.curPiece.shape); |
|
204 } |
|
205 } |
|
206 } |
|
207 |
|
208 TetrixBoard.prototype.onPaintNextPiece = function(painter) { |
|
209 for (var i = 0; i < 4; ++i) { |
|
210 var x = this.nextPiece.getX(i) - this.nextPiece.minX; |
|
211 var y = this.nextPiece.getY(i) - this.nextPiece.minY; |
|
212 this.ui.drawSquare(painter, x, y, this.nextPiece.shape); |
|
213 } |
|
214 } |
|
215 |
|
216 TetrixBoard.prototype.onKeyPress = function(key) { |
|
217 if (!this.isStarted || this.isPaused || (this.curPiece.shape == TetrixShape.NoShape)) |
|
218 return; |
|
219 this.inKeyPress = true; |
|
220 switch (key) { |
|
221 case Qt.Key_Left: |
|
222 this.tryMove(this.curPiece, this.curX - 1, this.curY); |
|
223 break; |
|
224 case Qt.Key_Right: |
|
225 this.tryMove(this.curPiece, this.curX + 1, this.curY); |
|
226 break; |
|
227 case Qt.Key_Down: |
|
228 this.tryMove(this.curPiece.rotatedRight(), this.curX, this.curY); |
|
229 break; |
|
230 case Qt.Key_Up: |
|
231 this.tryMove(this.curPiece.rotatedLeft(), this.curX, this.curY); |
|
232 break; |
|
233 case Qt.Key_Space: |
|
234 this.dropDown(); |
|
235 break; |
|
236 case Qt.Key_D: |
|
237 this.oneLineDown(); |
|
238 break; |
|
239 } |
|
240 this.inKeyPress = false; |
|
241 if (this.isStarted && !this.ui.timer.active) |
|
242 this.ui.timer.start(this.timeoutTime()); |
|
243 } |
|
244 |
|
245 TetrixBoard.prototype.onTimer = function() { |
|
246 if (this.isWaitingAfterLine) { |
|
247 this.isWaitingAfterLine = false; |
|
248 this.newPiece(); |
|
249 this.ui.timer.start(this.timeoutTime()); |
|
250 } else { |
|
251 if (!this.inKeyPress) { |
|
252 this.oneLineDown(); |
|
253 if (this.isStarted && !this.ui.timer.active) |
|
254 this.ui.timer.start(this.timeoutTime()); |
|
255 } |
|
256 } |
|
257 } |
|
258 |
|
259 TetrixBoard.prototype.timeoutTime = function() { |
|
260 return 1000 / (1 + this.level); |
|
261 } |