Esempio n. 1
0
//旋转变换根据http://tetris.wikia.com/wiki/SRS
void Game::rotateTetromino(bool clockwise)
{
    //保存旋转后的数组形状,用来检测碰撞
    int rotated[TETROMINO_SIZE][TETROMINO_SIZE];
    
    //如果是O形,不用旋转
    if(mFallingBlock.type == TETROMINO_O)
    {
        return;
    }
    
    setMatrixCells(&rotated[0][0], TETROMINO_SIZE, TETROMINO_SIZE, EMPTY_CELL);
    
    //将旋转后的cell存入rotated数组
    for (int i = 0; i < mFallingBlock.size; ++i) {
        for (int j = 0; j < mFallingBlock.size; ++j) {
            if(clockwise)
            {
                rotated[mFallingBlock.size - j - 1][i] = mFallingBlock.cells[i][j];
            }
            else
            {
                rotated[j][mFallingBlock.size - i - 1] = mFallingBlock.cells[i][j];
            }
        }
    }
    
    /*
     这里为了简单,我不允许kick wall,也就是当方块贴住墙壁的时候,不允许旋转
    */
    for (int i = 0; i < mFallingBlock.size; ++i) {
        for (int j = 0; j < mFallingBlock.size; ++j) {
            if (rotated[i][j] != EMPTY_CELL) {
                //检测和墙壁的碰撞
                if (mFallingBlock.x + i < 0     //碰到左墙壁
                    //必须在墙内
                    || mFallingBlock.x + i >= BOARD_TILEMAP_WIDTH    //碰到右墙壁
                    || mFallingBlock.y + j >= BOARD_TILEMAP_HEIGHT) {//碰到地面
                    return;
                }
                
                //检测和已有方块的碰撞
                if(mMap[mFallingBlock.x + i][mFallingBlock.y + j] != EMPTY_CELL) {
                    return;
                }
            }
        }
    }
    
    //如果没有碰撞,那么就用rotated替代mFallingBlock
    for (int i = 0; i < mFallingBlock.size; ++i) {
        for (int j = 0; j < mFallingBlock.size; ++j) {
            mFallingBlock.cells[i][j] = rotated[i][j];
        }
    }
    onTetrominoMoved();
}
Esempio n. 2
0
File: game.c Progetto: ex/blocks
/* 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
}
Esempio n. 3
0
// 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
}
Esempio n. 4
0
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;
}
Esempio n. 5
0
File: game.c Progetto: ex/blocks
/*
 * 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);
}
Esempio n. 6
0
File: game.c Progetto: ex/blocks
/*
 * Rotate falling tetromino. If there are no collisions when the
 * tetromino is rotated this modifies the tetromino's cell buffer.
 */
void rotateTetromino(StcGame *game, int clockwise) {
    int i, j;
#ifdef STC_WALL_KICK_ENABLED
    int wallDisplace;
#endif
    int rotated[TETROMINO_SIZE][TETROMINO_SIZE];  /* temporary array to hold rotated cells */

    /* If TETROMINO_O is falling return immediately */
    if (game->fallingBlock.type == TETROMINO_O) {
        return; /* rotation doesn't require any changes */
    }

    /* Initialize rotated cells to blank */
    setMatrixCells(&rotated[0][0], TETROMINO_SIZE, TETROMINO_SIZE, EMPTY_CELL);

    /* Copy rotated cells to the temporary array */
    for (i = 0; i < game->fallingBlock.size; ++i) {
        for (j = 0; j < game->fallingBlock.size; ++j) {
            if (clockwise) {
                rotated[game->fallingBlock.size - j - 1][i] = game->fallingBlock.cells[i][j];
            } else {
                rotated[j][game->fallingBlock.size - i - 1] = game->fallingBlock.cells[i][j];
            }
        }
    }
#ifdef STC_WALL_KICK_ENABLED
    wallDisplace = 0;

    /* Check collision with left wall */
    if (game->fallingBlock.x < 0) {
        for (i = 0; (wallDisplace == 0) && (i < -game->fallingBlock.x); ++i) {
            for (j = 0; j < game->fallingBlock.size; ++j) {
                if (rotated[i][j] != EMPTY_CELL) {
                    wallDisplace = i - game->fallingBlock.x;
                    break;
                }
            }
        }
    }
    /* Or check collision with right wall */
    else if (game->fallingBlock.x > BOARD_TILEMAP_WIDTH - game->fallingBlock.size) {
        i = game->fallingBlock.size - 1;
        for (; (wallDisplace == 0) && (i >= BOARD_TILEMAP_WIDTH - game->fallingBlock.x); --i) {
            for (j = 0; j < game->fallingBlock.size; ++j) {
                if (rotated[i][j] != EMPTY_CELL) {
                    wallDisplace = -game->fallingBlock.x - i + BOARD_TILEMAP_WIDTH - 1;
                    break;
                }
            }
        }
    }

    /* Check collision with board floor and other cells on board */
    for (i = 0; i < game->fallingBlock.size; ++i) {
        for (j = 0; j < game->fallingBlock.size; ++j) {
            if (rotated[i][j] != EMPTY_CELL) {
                /* Check collision with bottom border of the map */
                if (game->fallingBlock.y + j >= BOARD_TILEMAP_HEIGHT) {
                    return; /* there was collision therefore return */
                }
                /* Check collision with existing cells in the map */
                if (game->map[i + game->fallingBlock.x + wallDisplace][j + game->fallingBlock.y] != EMPTY_CELL) {
                    return; /* there was collision therefore return */
                }
            }
        }
    }
    /* Move the falling piece if there was wall collision and it's a legal move */
    if (wallDisplace != 0) {
        game->fallingBlock.x += wallDisplace;
    }
#else
    /* Check collision of the temporary array */
    for (i = 0; i < game->fallingBlock.size; ++i) {
        for (j = 0; j < game->fallingBlock.size; ++j) {
            if (rotated[i][j] != EMPTY_CELL) {
                /* Check collision with left, right or bottom borders of the map */
                if ((game->fallingBlock.x + i < 0) || (game->fallingBlock.x + i >= BOARD_TILEMAP_WIDTH)
                        || (game->fallingBlock.y + j >= BOARD_TILEMAP_HEIGHT)) {
                    return; /* there was collision therefore return */
                }
                /* Check collision with existing cells in the map */
                if (game->map[i + game->fallingBlock.x][j + game->fallingBlock.y] != EMPTY_CELL) {
                    return; /* there was collision therefore return */
                }
            }
        }
    }
#endif
    /* There are no collisions, replace tetromino cells with rotated cells */
    for (i = 0; i < TETROMINO_SIZE; ++i) {
        for (j = 0; j < TETROMINO_SIZE; ++j) {
            game->fallingBlock.cells[i][j] = rotated[i][j];
        }
    }
    onTetrominoMoved(game);
}
Esempio n. 7
0
// 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();
}
Esempio n. 8
0
// Rotate falling tetromino. If there are no collisions when the
// tetromino is rotated this modifies the tetromino's cell buffer.
void Game::rotateTetromino(bool clockwise)
{
    int i, j;
    int rotated[TETROMINO_SIZE][TETROMINO_SIZE];  // temporary array to hold rotated cells

    // If TETROMINO_O is falling return immediately
    if (mFallingBlock.type == TETROMINO_O)
    {
        return; // rotation doesn't require any changes
    }

    // Initialize rotated cells to blank
    setMatrixCells(&rotated[0][0], TETROMINO_SIZE, TETROMINO_SIZE, EMPTY_CELL);

    // Copy rotated cells to the temporary array
    for (i = 0; i < mFallingBlock.size; ++i)
    {
        for (j = 0; j < mFallingBlock.size; ++j)
        {
            if (clockwise)
            {
                rotated[mFallingBlock.size - j - 1][i] = mFallingBlock.cells[i][j];
            }
            else
            {
                rotated[j][mFallingBlock.size - i - 1] = mFallingBlock.cells[i][j];
            }
        }
    }
#define STC_WALL_KICK_ENABLED
#ifdef STC_WALL_KICK_ENABLED
    int wallDisplace = 0;

    // Check collision with left wall
    if (mFallingBlock.x < 0)
    {
        for (i = 0; (wallDisplace == 0) && (i < -mFallingBlock.x); ++i)
        {
            for (j = 0; j < mFallingBlock.size; ++j)
            {
                if (rotated[i][j] != EMPTY_CELL)
                {
                    wallDisplace = i - mFallingBlock.x;
                    break;
                }
            }
        }
    }
    // Or check collision with right wall
    else if (mFallingBlock.x > BOARD_TILEMAP_WIDTH - mFallingBlock.size)
    {
        i = mFallingBlock.size - 1;
        for (; (wallDisplace == 0) && (i >= BOARD_TILEMAP_WIDTH - mFallingBlock.x); --i)
        {
            for (j = 0; j < mFallingBlock.size; ++j)
            {
                if (rotated[i][j] != EMPTY_CELL)
                {
                    wallDisplace = -mFallingBlock.x - i + BOARD_TILEMAP_WIDTH - 1;
                    break;
                }
            }
        }
    }

    // Check collision with board floor and other cells on board
    for (i = 0; i < mFallingBlock.size; ++i)
    {
        for (j = 0; j < mFallingBlock.size; ++j)
        {
            if (rotated[i][j] != EMPTY_CELL)
            {
                // Check collision with bottom border of the map
                if (mFallingBlock.y + j >= BOARD_TILEMAP_HEIGHT)
                {
                    return; // there was collision therefore return
                }

                // Check collision with existing cells in the map
                if (mMap[i + mFallingBlock.x + wallDisplace][j + mFallingBlock.y] != EMPTY_CELL)
                {
                    return; // there was collision therefore return
                }
            }
        }
    }

    // Move the falling piece if there was wall collision and it's a legal move
    if (wallDisplace != 0)
    {
        mFallingBlock.x += wallDisplace;
    }
#else
    // Check collision of the temporary array
    for (i = 0; i < mFallingBlock.size; ++i)
    {
        for (j = 0; j < mFallingBlock.size; ++j)
        {
            if (rotated[i][j] != EMPTY_CELL)
            {
                // Check collision with left, right or bottom borders of the map
                if ((mFallingBlock.x + i < 0)
                        || (mFallingBlock.x + i >= BOARD_TILEMAP_WIDTH)
                        || (mFallingBlock.y + j >= BOARD_TILEMAP_HEIGHT))
                {
                    return; // there was collision therefore return
                }

                // Check collision with existing cells in the map
                if (mMap[i + mFallingBlock.x][j + mFallingBlock.y] != EMPTY_CELL)
                {
                    return; // there was collision therefore return
                }
            }
        }
    }
#endif // STC_WALL_KICK_ENABLED

    // There are no collisions, replace tetromino cells with rotated cells
    for (i = 0; i < TETROMINO_SIZE; ++i)
    {
        for (j = 0; j < TETROMINO_SIZE; ++j)
        {
            mFallingBlock.cells[i][j] = rotated[i][j];
        }
    }
    onTetrominoMoved();
}
Esempio n. 9
0
//将方块向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();
}