Stefan Schuermans commited on 2019-07-14 18:59:44
Showing 2 changed files, with 89 additions and 8 deletions.
... | ... |
@@ -151,8 +151,8 @@ void Tetris::opConnRecvKey(OpConn *pConn, char key) |
151 | 151 |
} |
152 | 152 |
|
153 | 153 |
/** normal keys for controlling game, |
154 |
- deactivated if dropping stone */ |
|
155 |
- if (m_dropping) { |
|
154 |
+ deactivated if dropping stone or rows blinking */ |
|
155 |
+ if (m_dropping || m_blinking > 0) { |
|
156 | 156 |
return; |
157 | 157 |
} |
158 | 158 |
|
... | ... |
@@ -252,11 +252,17 @@ void Tetris::reinitialize() |
252 | 252 |
color2data(m_fileStoneColor, m_stoneColor); |
253 | 253 |
// get values |
254 | 254 |
valueFromFile(m_fileDelay, c_delayDescr, m_delay); |
255 |
+ valueFromFile(m_fileDropDelay, c_dropDelayDescr, m_dropDelay); |
|
256 |
+ valueFromFile(m_fileBlinkDelay, c_blinkDelayDescr, m_blinkDelay); |
|
255 | 257 |
|
256 | 258 |
// initialize field: empty |
257 | 259 |
m_field.clear(); |
258 | 260 |
m_field.resize(m_height * m_width, -1); |
259 | 261 |
|
262 |
+ // initialize blinking rows: no row blinking |
|
263 |
+ m_rowsBlink.clear(); |
|
264 |
+ m_rowsBlink.resize(m_height, false); |
|
265 |
+ |
|
260 | 266 |
// start with new stone |
261 | 267 |
newStone(); |
262 | 268 |
|
... | ... |
@@ -273,14 +279,16 @@ void Tetris::redraw() |
273 | 279 |
// draw background |
274 | 280 |
rectFill(0, m_height, 0, m_width, m_backgroundColor); |
275 | 281 |
|
276 |
- // draw fixed pixels |
|
282 |
+ // draw fixed pixels, respect blinking rows |
|
277 | 283 |
for (int y = 0, i = 0; y < m_height; ++y) { |
284 |
+ if (! (m_blinking & 1) || ! m_rowsBlink.at(y)) { |
|
278 | 285 |
for (int x = 0; x < m_width; ++x, ++i) { |
279 | 286 |
if (m_field.at(i) >= 0) { |
280 | 287 |
pixel(y, x, m_stoneColor); |
281 | 288 |
} |
282 | 289 |
} |
283 | 290 |
} |
291 |
+ } |
|
284 | 292 |
|
285 | 293 |
// draw current stone |
286 | 294 |
drawStone(m_stone, m_rot, m_posY, m_posX); |
... | ... |
@@ -292,6 +300,43 @@ void Tetris::redraw() |
292 | 300 |
/// process next time step of game |
293 | 301 |
void Tetris::timeStep() |
294 | 302 |
{ |
303 |
+ // blinking of completed rows |
|
304 |
+ if (m_blinking > 0) { |
|
305 |
+ |
|
306 |
+ // blink rows |
|
307 |
+ ++m_blinking; |
|
308 |
+ |
|
309 |
+ // end of blinking -> remove blinking rows, new stone |
|
310 |
+ if (m_blinking >= 8) { |
|
311 |
+ // remove blinking rows |
|
312 |
+ for (int b = 0; b < m_height; ++b) { |
|
313 |
+ if (m_rowsBlink.at(b)) { |
|
314 |
+ // move rows 0..b-1 one row down, i.e., to rows 1..b |
|
315 |
+ for (int y = b, i = b * m_width + m_width - 1; y > 0; --y) { |
|
316 |
+ for (int x = m_width - 1; x >= 0; --x, --i) { |
|
317 |
+ m_field.at(i) = m_field.at(i - m_width); |
|
318 |
+ } |
|
319 |
+ } |
|
320 |
+ // clear first row |
|
321 |
+ for (int x = 0; x < m_width; ++x) { |
|
322 |
+ m_field.at(x) = -1; |
|
323 |
+ } |
|
324 |
+ // row not blinking any more |
|
325 |
+ m_rowsBlink.at(b) = false; |
|
326 |
+ } |
|
327 |
+ } |
|
328 |
+ // blinking done |
|
329 |
+ m_blinking = 0; |
|
330 |
+ // new stone |
|
331 |
+ newStone(); |
|
332 |
+ } |
|
333 |
+ |
|
334 |
+ // redraw image and send frame |
|
335 |
+ redraw(); |
|
336 |
+ |
|
337 |
+ // falling stone |
|
338 |
+ } else { |
|
339 |
+ |
|
295 | 340 |
// stone can move down by one pixel |
296 | 341 |
if (checkStoneFit(m_stone, m_rot, m_posY + 1, m_posX)) { |
297 | 342 |
// move stone down by one pixel |
... | ... |
@@ -305,17 +350,50 @@ void Tetris::timeStep() |
305 | 350 |
// add stone permanently to field at current position |
306 | 351 |
freezeStone(m_stone, m_rot, m_posY, m_posX); |
307 | 352 |
drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: frozen color |
308 |
- // prepare new stone |
|
309 |
- newStone(); |
|
353 |
+ // no current stone any more |
|
354 |
+ m_stone = -1; |
|
355 |
+ // check for completed rows, (afterwards: new stone) |
|
356 |
+ checkComplete(); |
|
310 | 357 |
} |
311 | 358 |
|
312 | 359 |
// send updated image buffer as frame |
313 | 360 |
sendFrame(); |
314 | 361 |
|
362 |
+ } // falling stone |
|
363 |
+ |
|
315 | 364 |
// request next time step |
316 | 365 |
planTimeStep(); |
317 | 366 |
} |
318 | 367 |
|
368 |
+/// check for completed rows to disappear (new stone afterwards) |
|
369 |
+void Tetris::checkComplete() |
|
370 |
+{ |
|
371 |
+ // collect y coordinated of completed rows -> m_rowsBlink |
|
372 |
+ bool blink = false; |
|
373 |
+ for (int y = 0, i = 0; y < m_height; ++y) { |
|
374 |
+ bool complete = true; |
|
375 |
+ for (int x = 0; x < m_width; ++x, ++i) { |
|
376 |
+ if (m_field.at(i) < 0) { |
|
377 |
+ complete = false; |
|
378 |
+ } |
|
379 |
+ } |
|
380 |
+ m_rowsBlink.at(y) = complete; |
|
381 |
+ if (complete) { |
|
382 |
+ blink = true; |
|
383 |
+ } |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ // no completed rows -> new stone |
|
387 |
+ if (! blink) { |
|
388 |
+ newStone(); |
|
389 |
+ } |
|
390 |
+ |
|
391 |
+ // start blinking (start with rows visible, last bit == 0) |
|
392 |
+ else { |
|
393 |
+ m_blinking = 2; |
|
394 |
+ } |
|
395 |
+} |
|
396 |
+ |
|
319 | 397 |
/// set up a new stone |
320 | 398 |
void Tetris::newStone() |
321 | 399 |
{ |
... | ... |
@@ -121,6 +121,9 @@ protected: |
121 | 121 |
/// process next time step of game |
122 | 122 |
virtual void timeStep(); |
123 | 123 |
|
124 |
+ /// check for completed rows to disappear (new stone afterwards) |
|
125 |
+ void checkComplete(); |
|
126 |
+ |
|
124 | 127 |
/// set up a new stone |
125 | 128 |
void newStone(); |
126 | 129 |
|
... | ... |
@@ -181,12 +184,12 @@ protected: |
181 | 184 |
int m_posX; ///< x position of current stone |
182 | 185 |
int m_posY; ///< y position of current stone |
183 | 186 |
bool m_dropping; ///< whether currently dropping a stone |
184 |
- int m_blinking; ///< step of blinking: 0 not blinking |
|
187 |
+ int m_blinking; ///< step of blinking: 0 not blinking, lsb == 0 -> visible |
|
185 | 188 |
|
186 | 189 |
/// tetris field (y * m_width + x), -1 for free, >= 0 for pixel from stone |
187 | 190 |
std::vector<int> m_field; |
188 |
- /// sorted y indices of rows that are currently blinking |
|
189 |
- std::vector<int> m_rowsBlink; |
|
191 |
+ /// rows that are currently blinking (bool for each row, true when blinking) |
|
192 |
+ std::vector<bool> m_rowsBlink; |
|
190 | 193 |
}; // class Tetris |
191 | 194 |
|
192 | 195 |
} // namespace Blinker |
193 | 196 |