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 |