tetris WIP: move/freeze stones
Stefan Schuermans

Stefan Schuermans commited on 2019-07-14 17:51:57
Showing 2 changed files, with 114 additions and 16 deletions.

... ...
@@ -138,7 +138,59 @@ void Tetris::opConnRecvKey(OpConn *pConn, char key)
138 138
 
139 139
   // normal keys for controlling game
140 140
 
141
+  // move left
142
+  if (key == '4') {
143
+    if (checkStoneFit(m_stone, m_rot, m_posY, m_posX - 1)) {
144
+      wipeStone(m_stone, m_rot, m_posY, m_posX);
145
+      m_posX -= 1;
146
+      drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
147
+    }
148
+    return;
149
+  }
150
+
151
+  // move right
152
+  if (key == '6') {
153
+    if (checkStoneFit(m_stone, m_rot, m_posY, m_posX + 1)) {
154
+      wipeStone(m_stone, m_rot, m_posY, m_posX);
155
+      m_posX += 1;
156
+      drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
157
+    }
158
+    return;
159
+  }
160
+
161
+  // rotate left
162
+  if (key == '1') {
163
+    int new_rot = m_rot - 1;
164
+    if (new_rot < 0) {
165
+      new_rot = c_rotCnt - 1;
166
+    }
167
+    if (checkStoneFit(m_stone, new_rot, m_posY, m_posX)) {
168
+      wipeStone(m_stone, m_rot, m_posY, m_posX);
169
+      m_rot = new_rot;
170
+      drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
171
+    }
172
+    return;
173
+  }
174
+
175
+  // rotate right
176
+  if (key == '2' || key == '3') {
177
+    int new_rot = m_rot + 1;
178
+    if (new_rot >= c_rotCnt) {
179
+      new_rot = 0;
180
+    }
181
+    if (checkStoneFit(m_stone, new_rot, m_posY, m_posX)) {
182
+      wipeStone(m_stone, m_rot, m_posY, m_posX);
183
+      m_rot = new_rot;
184
+      drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
185
+    }
186
+    return;
187
+  }
188
+
189
+  // drop stone
190
+  if (key == '8') {
141 191
     // TODO
192
+    return;
193
+  }
142 194
 }
143 195
 
144 196
 /**
... ...
@@ -217,13 +269,22 @@ void Tetris::redraw()
217 269
 /// process next time step of game
218 270
 void Tetris::timeStep()
219 271
 {
220
-  // FIXME
221
-  if (m_posY >= m_height + 2) {
222
-    newStone();
223
-  }
272
+  // stone can move down by one pixel
273
+  if (checkStoneFit(m_stone, m_rot, m_posY + 1, m_posX)) {
274
+    // move stone down by one pixel
224 275
     wipeStone(m_stone, m_rot, m_posY, m_posX);
225 276
     m_posY += 1;
226
-  drawStone(m_stone, m_rot, m_posY, m_posX);
277
+    drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: active color
278
+  }
279
+
280
+  // stone cannot move down by one pixel
281
+  else {
282
+    // add stone permanently to field at current position
283
+    freezeStone(m_stone, m_rot, m_posY, m_posX);
284
+    drawStone(m_stone, m_rot, m_posY, m_posX); // TODO: frozen color
285
+    // prepare new stone
286
+    newStone();
287
+  }
227 288
 
228 289
   // send updated image buffer as frame
229 290
   sendFrame();
... ...
@@ -262,33 +323,65 @@ void Tetris::planTimeStep()
262 323
   setTimeStep(Time::now() + stepTime);
263 324
 }
264 325
 
326
+/// get rotatation of stone from stone/rotation index (or NULL in invalid)
327
+Tetris::RotStone const * Tetris::getRotStone(int stone, int rot)
328
+{
329
+  if (! checkLimitInt(stone, 0, c_stoneCnt -1) ||
330
+      ! checkLimitInt(rot, 0, c_rotCnt - 1)) {
331
+    return NULL; // invalid stone or rotation
332
+  }
333
+  return &c_stones[stone].rot[rot];
334
+}
335
+
265 336
 /// check if stone fits at position
266 337
 bool Tetris::checkStoneFit(int stone, int rot, int y, int x) const
267 338
 {
268 339
   // get rotation of stone
269
-  if (! checkLimitInt(stone, 0, c_stoneCnt -1) ||
270
-      ! checkLimitInt(rot, 0, c_rotCnt - 1)) {
340
+  RotStone const *rotStone = getRotStone(stone, rot);
341
+  if (! rotStone) {
271 342
     return false; // invalid stone or rotation -> does not fit
272 343
   }
273
-  RotStone const &rotStone = c_stones[stone].rot[rot];
274 344
 
275 345
   // check pixels
276 346
   for (int p = 0; p < c_pixelCnt; ++p) {
277
-    int py = y + rotStone.pixels[p].y;
278
-    int px = x + rotStone.pixels[p].x;
279
-    if (py >= m_height - 1 || ! checkLimitInt(px, 0, m_width - 1)) {
347
+    int py = y + rotStone->pixels[p].y;
348
+    int px = x + rotStone->pixels[p].x;
349
+    if (py > m_height - 1 || ! checkLimitInt(px, 0, m_width - 1)) {
280 350
       return false; // outside field (except at top) -> does not fit
281 351
     }
352
+    if (py >= 0) { // do not check above top
282 353
       int pi = py * m_width + px;
283 354
       if (m_field.at(pi) >= 0) {
284 355
         return false; // occupixed pixel -> does not fit
285 356
       }
286 357
     }
358
+  }
287 359
 
288 360
   // all checks passed -> stone fits
289 361
   return true;
290 362
 }
291 363
 
364
+/// freeze stone to field at position
365
+void Tetris::freezeStone(int stone, int rot, int y, int x)
366
+{
367
+  // get rotation of stone
368
+  RotStone const *rotStone = getRotStone(stone, rot);
369
+  if (! rotStone) {
370
+    return; // invalid stone or rotation -> nothing to do
371
+  }
372
+
373
+  // add pixels to field
374
+  for (int p = 0; p < c_pixelCnt; ++p) {
375
+    int py = y + rotStone->pixels[p].y;
376
+    int px = x + rotStone->pixels[p].x;
377
+    if (checkLimitInt(py, 0, m_height - 1) &&
378
+        checkLimitInt(px, 0, m_width - 1)) {
379
+      int pi = py * m_width + px;
380
+      m_field.at(pi) = stone; // mark pixel in field with stone index
381
+    }
382
+  }
383
+}
384
+
292 385
 /// draw a stone to image buffer
293 386
 void Tetris::drawStone(int stone, int rot, int y, int x)
294 387
 {
... ...
@@ -306,15 +399,14 @@ void Tetris::colorStone(int stone, int rot, int y, int x,
306 399
                         ColorData const &color)
307 400
 {
308 401
   // get rotation of stone
309
-  if (! checkLimitInt(stone, 0, c_stoneCnt -1) ||
310
-      ! checkLimitInt(rot, 0, c_rotCnt - 1)) {
402
+  RotStone const *rotStone = getRotStone(stone, rot);
403
+  if (! rotStone) {
311 404
     return; // invalid stone or rotation -> nothing to do
312 405
   }
313
-  RotStone const &rotStone = c_stones[stone].rot[rot];
314 406
 
315 407
   // color pixels
316 408
   for (int p = 0; p < c_pixelCnt; ++p) {
317
-    pixel(y + rotStone.pixels[p].y, x + rotStone.pixels[p].x, color);
409
+    pixel(y + rotStone->pixels[p].y, x + rotStone->pixels[p].x, color);
318 410
   }
319 411
 }
320 412
 
... ...
@@ -382,7 +474,7 @@ int const Tetris::c_pixelCnt = sizeof(Tetris::RotStone::pixels) /
382 474
                                sizeof(Tetris::RotStone::pixels[0]);
383 475
 
384 476
 /// descriptor for delay value
385
-Tetris::ValueDescr const Tetris::c_delayDescr = { 200, 100, 500 };
477
+Tetris::ValueDescr const Tetris::c_delayDescr = { 400, 200, 1000 };
386 478
 
387 479
 } // namespace Blinker
388 480
 
... ...
@@ -127,9 +127,15 @@ protected:
127 127
   /// set time for next time step of game - or unset if not needed
128 128
   void planTimeStep();
129 129
 
130
+  /// get rotatation of stone from stone/rotation index (or NULL in invalid)
131
+  static RotStone const * getRotStone(int stone, int rot);
132
+
130 133
   /// check if stone fits at position
131 134
   bool checkStoneFit(int stone, int rot, int y, int x) const;
132 135
 
136
+  /// freeze stone to field at position
137
+  void freezeStone(int stone, int rot, int y, int x);
138
+
133 139
   /// draw a stone to image buffer
134 140
   void drawStone(int stone, int rot, int y, int x);
135 141
 
136 142