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 |