/* Start a new game */ static void startGame(StcGame *game) { int i; /* Initialize game data */ game->errorCode = ERROR_NONE; game->data->systemTime = platformGetSystemTime(); game->data->lastFallTime = game->data->systemTime; game->data->isOver = 0; game->isPaused = 0; game->showPreview = 1; game->data->events = EVENT_NONE; game->data->fallingDelay = STC_INIT_DELAY_FALL; #ifdef STC_SHOW_GHOST_PIECE game->showShadow = 1; #endif /* Initialize game statistics */ game->stats.score = 0; game->stats.lines = 0; game->stats.totalPieces = 0; game->stats.level = 0; for (i = 0; i < TETROMINO_TYPES; ++i) { game->stats.pieces[i] = 0; } /* Initialize game tile map */ setMatrixCells(&game->map[0][0], BOARD_TILEMAP_WIDTH, BOARD_TILEMAP_HEIGHT, EMPTY_CELL); /* Initialize falling tetromino */ setTetromino(platformRandom() % TETROMINO_TYPES, &game->fallingBlock); game->fallingBlock.x = (BOARD_TILEMAP_WIDTH - game->fallingBlock.size) / 2; game->fallingBlock.y = 0; /* Initialize preview tetromino */ setTetromino(platformRandom() % TETROMINO_TYPES, &game->nextBlock); /* Initialize events */ onTetrominoMoved(game); /* Initialize delayed autoshift */ game->data->delayLeft = -1; game->data->delayRight = -1; game->data->delayDown = -1; #ifdef STC_AUTO_ROTATION game->data->delayRotation = -1; #endif }
// Start a new game void Game::start() { // Initialize game data mErrorCode = ERROR_NONE; mSystemTime = mPlatform->getSystemTime(); mLastFallTime = mSystemTime; mIsOver = false; mIsPaused = false; mShowPreview = true; mEvents = EVENT_NONE; mFallingDelay = INIT_DELAY_FALL; #ifdef STC_SHOW_GHOST_PIECE mShowShadow = true; #endif // Initialize game statistics mStats.score = 0; mStats.lines = 0; mStats.totalPieces = 0; mStats.level = 0; for (int i = 0; i < TETROMINO_TYPES; ++i) { mStats.pieces[i] = 0; } // Initialize game tile map setMatrixCells(&mMap[0][0], BOARD_TILEMAP_WIDTH, BOARD_TILEMAP_HEIGHT, EMPTY_CELL); // Initialize falling tetromino setTetromino(mPlatform->random() % TETROMINO_TYPES, &mFallingBlock); mFallingBlock.x = (BOARD_TILEMAP_WIDTH - mFallingBlock.size) / 2; mFallingBlock.y = 0; // Initialize preview tetromino setTetromino(mPlatform->random() % TETROMINO_TYPES, &mNextBlock); // Initialize events onTetrominoMoved(); // Initialize delayed autoshift mDelayLeft = -1; mDelayRight = -1; mDelayDown = -1; #ifdef STC_AUTO_ROTATION mDelayRotation = -1; #endif }
void Game::start() { mErrorCode = ERROR_NONE; mSystemTime = mPlatform->getSystemTime(); mLastFallTime = mSystemTime; mIsOver = false; mIsPaused = false; mShowPreview = true; mEvents = EVENT_NONE; mFallingDelay = INIT_DELAY_FALL; mShowShadow = false; mStats.score = 0; mStats.lines = 0; mStats.totalPieces = 0; mStats.level = 0; for (int i = 0; i < TETROMINO_TYPES; ++i) { mStats.pieces[i] = 0; } //初始化整个棋盘 setMatrixCells(&mMap[0][0], BOARD_TILEMAP_WIDTH, BOARD_TILEMAP_HEIGHT, EMPTY_CELL); //开始时随机设置一个nextblock作为第一个形状 setTetromino(mPlatform->random() % TETROMINO_TYPES, &mFallingBlock); //初始化为mFallingBlock的up-left mFallingBlock.x = BOARD_TILEMAP_WIDTH / 2 - mFallingBlock.size / 2; mFallingBlock.y = 0; setTetromino(mPlatform->random() % TETROMINO_TYPES, &mNextBlock); onTetrominoMoved(); mDelayDown = -1; mDelayLeft = -1; mDelayRight = -1; mDelayRotation = -1; }
/* * Move tetromino in the direction specified by (x, y) (in tile units) * This function detects if there are filled rows or if the move * lands a falling tetromino, also checks for game over condition. */ static void moveTetromino(StcGame *game, int x, int y) { int i, j, hasFullRow, numFilledRows; /* Check if the move would create a collision */ if (checkCollision(game, x, y)) { /* In case of collision check if move was downwards (y == 1) */ if (y == 1) { /* Check if collision occurs when the falling * tetromino is on the 1st or 2nd row */ if (game->fallingBlock.y <= 1) { game->data->isOver = 1; /* if this happens the game is over */ } else { /* The falling tetromino has reached the bottom, * so we copy their cells to the board map */ for (i = 0; i < game->fallingBlock.size; ++i) { for (j = 0; j < game->fallingBlock.size; ++j) { if (game->fallingBlock.cells[i][j] != EMPTY_CELL) { game->map[game->fallingBlock.x + i][game->fallingBlock.y + j] = game->fallingBlock.cells[i][j]; } } } /* Check if the landing tetromino has created full rows */ numFilledRows = 0; for (j = 1; j < BOARD_TILEMAP_HEIGHT; ++j) { hasFullRow = 1; for (i = 0; i < BOARD_TILEMAP_WIDTH; ++i) { if (game->map[i][j] == EMPTY_CELL) { hasFullRow = 0; break; } } /* If we found a full row we need to remove that row from the map * we do that by just moving all the above rows one row below */ if (hasFullRow != 0) { for (x = 0; x < BOARD_TILEMAP_WIDTH; ++x) { for (y = j; y > 0; --y) { game->map[x][y] = game->map[x][y - 1]; } } numFilledRows++; /* increase filled row counter */ } } /* Update game statistics */ if (numFilledRows > 0) { onFilledRows(game, numFilledRows); } game->stats.totalPieces++; game->stats.pieces[game->fallingBlock.type]++; /* Use preview tetromino as falling tetromino. * Copy preview tetromino for falling tetromino */ for (i = 0; i < TETROMINO_SIZE; ++i) { for (j = 0; j < TETROMINO_SIZE; ++j) { game->fallingBlock.cells[i][j] = game->nextBlock.cells[i][j]; } } game->fallingBlock.size = game->nextBlock.size; game->fallingBlock.type = game->nextBlock.type; /* Reset position */ game->fallingBlock.y = 0; game->fallingBlock.x = (BOARD_TILEMAP_WIDTH - game->fallingBlock.size) / 2; onTetrominoMoved(game); /* Create next preview tetromino */ setTetromino(platformRandom() % TETROMINO_TYPES, &game->nextBlock); } } } else { /* There are no collisions, just move the tetromino */ game->fallingBlock.x += x; game->fallingBlock.y += y; } onTetrominoMoved(game); }
// Move tetromino in the direction specified by (x, y) (in tile units) // This function detects if there are filled rows or if the move // lands a falling tetromino, also checks for game over condition. void Game::moveTetromino(int x, int y) { int i, j; // Check if the move would create a collision if (checkCollision(x, y)) { // In case of collision check if move was downwards (y == 1) if (y == 1) { // Check if collision occurs when the falling // tetromino is on the 1st or 2nd row if (mFallingBlock.y <= 1) { mIsOver = true; // if this happens the game is over } else { // The falling tetromino has reached the bottom, // so we copy their cells to the board map for (i = 0; i < mFallingBlock.size; ++i) { for (j = 0; j < mFallingBlock.size; ++j) { if (mFallingBlock.cells[i][j] != EMPTY_CELL) { mMap[mFallingBlock.x + i][mFallingBlock.y + j] = mFallingBlock.cells[i][j]; } } } // Check if the landing tetromino has created full rows int numFilledRows = 0; for (j = 1; j < BOARD_TILEMAP_HEIGHT; ++j) { bool hasFullRow = true; for (i = 0; i < BOARD_TILEMAP_WIDTH; ++i) { if (mMap[i][j] == EMPTY_CELL) { hasFullRow = false; break; } } // If we found a full row we need to remove that row from the map // we do that by just moving all the above rows one row below if (hasFullRow) { for (x = 0; x < BOARD_TILEMAP_WIDTH; ++x) { for (y = j; y > 0; --y) { mMap[x][y] = mMap[x][y - 1]; } } numFilledRows++; // increase filled row counter } } // Update game statistics if (numFilledRows > 0) { onFilledRows(numFilledRows); } mStats.totalPieces++; mStats.pieces[mFallingBlock.type]++; // Use preview tetromino as falling tetromino. // Copy preview tetromino for falling tetromino for (i = 0; i < TETROMINO_SIZE; ++i) { for (j = 0; j < TETROMINO_SIZE; ++j) { mFallingBlock.cells[i][j] = mNextBlock.cells[i][j]; } } mFallingBlock.size = mNextBlock.size; mFallingBlock.type = mNextBlock.type; // Reset position mFallingBlock.y = 0; mFallingBlock.x = (BOARD_TILEMAP_WIDTH - mFallingBlock.size) / 2; onTetrominoMoved(); // Create next preview tetromino setTetromino(mPlatform->random() % TETROMINO_TYPES, &mNextBlock); } } } else { // There are no collisions, just move the tetromino mFallingBlock.x += x; mFallingBlock.y += y; } onTetrominoMoved(); }
//将方块向x,y方向移动 //检测是否与已有的cell冲突或者已经落地,同时检查游戏是否结束 void Game::moveTetromino(int x, int y) { //如果有冲突 if (checkCollision(x, y)) { //如果是往下移动的 if (y == 1) { //如果mFallingBlock刚向下移动了一格,或者还没移动就冲突了,代表游戏结束 if (mFallingBlock.y <= 1) { mIsOver = true; } else { //游戏没有结束,mFallingBlock落地 //那么把mFallingBlock内的元素copy到mMap中 for (int i = 0; i < mFallingBlock.size; ++i) { for (int j = 0; j < mFallingBlock.size; ++j) { if (mFallingBlock.cells[i][j] != EMPTY_CELL) { mMap[mFallingBlock.x + i][mFallingBlock.y + j] = mFallingBlock.cells[i][j]; } } } } //检查落地是否能够得分 /* x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x x 这是mMap的形状 */ int numFilledRows = 0; for (int j = 1; j < BOARD_TILEMAP_HEIGHT; ++j) { bool hasFullRow = true; for (int i = 0; i < BOARD_TILEMAP_WIDTH; ++i) { if (mMap[i][j] == EMPTY_CELL) { hasFullRow = false; break; } } //这一排满了 //将这一排上面的都往下移动一排,相当于消除这一排 //注意:(0, 0)点在上面图形的右上角,也就是屏幕的左上角 if (hasFullRow) { for (int t = j; t > 0; --t) { for (int p = 0; p < BOARD_TILEMAP_WIDTH; ++p) { mMap[p][t] = mMap[p][t - 1]; } } numFilledRows++; } } //计算分数 if (numFilledRows > 0) { onFilledRows(numFilledRows); } mStats.totalPieces++; mStats.pieces[mFallingBlock.type]++; //用下一个形状代替fallingblock for (int i = 0; i < TETROMINO_SIZE; ++i) { for (int j = 0; j < TETROMINO_SIZE; ++j) { mFallingBlock.cells[i][j] = mNextBlock.cells[i][j]; } } mFallingBlock.size = mNextBlock.size; mFallingBlock.type = mNextBlock.type; mFallingBlock.y = 0; mFallingBlock.x = BOARD_TILEMAP_WIDTH / 2 - mFallingBlock.size / 2; onTetrominoMoved(); //随机选择下一个方块 setTetromino(mPlatform->random() % TETROMINO_TYPES, &mNextBlock); } } else { //没有冲突,直接移动 mFallingBlock.x += x; mFallingBlock.y += y; } onTetrominoMoved(); }