基于SDL2自制俄罗斯方块

俄罗斯方块是一款十分经典的游戏,曾风靡全球,小时候玩得第一款电子游戏就是掌机俄罗斯方块。

基于SDL2自制俄罗斯方块_第1张图片

现在我们基于SDL2自制俄罗斯方块。

首先我们通过3维数组定义不同种类的方块,方块矩阵为4x4的二维数组,第三维为每种方块的变形种类。

const int TT_Blocks[TT_BLOCK_TYPE_NUM][TT_BLOCK_TRANS_NUM][TT_BLOCK_NUM_AREA_HEIGHT][TT_BLOCK_NUM_AREA_WIDTH] = {
    //TT_BLOCK_TYPE_NUM
    {
        //TT_BLOCK_TRANS_NUM
        {
            //TT_BLOCK_AREA_HEIGHT * TT_BLOCK_AREA_WIDTH
            {1, 1, 1, 1},
            {0, 0, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
         },
         {
            {0, 0, 1, 0},
            {0, 0, 1, 0},
            {0, 0, 1, 0},
            {0, 0, 1, 0}
         },
        {
            {1, 1, 1, 1},
            {0, 0, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
         },
         {
            {0, 0, 1, 0},
            {0, 0, 1, 0},
            {0, 0, 1, 0},
            {0, 0, 1, 0}
         }
    },
    {
        {
            {1, 0, 0, 0},
            {1, 1, 1, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {1, 1, 0, 0},
            {1, 0, 0, 0},
            {1, 0, 0, 0},
            {0, 0, 0, 0}
        },
       {
            {1, 1, 1, 0},
            {0, 0, 1, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {0, 1, 0, 0},
            {0, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0}
        }
    },
    {
        {
            {1, 1, 1, 0},
            {0, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {0, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 1, 0, 0},
            {0, 0, 0, 0}
        },
       {
            {0, 1, 0, 0},
            {1, 1, 1, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {1, 0, 0, 0},
            {1, 1, 0, 0},
            {1, 0, 0, 0},
            {0, 0, 0, 0}
        }
    },
    {
        {
            {1, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {1, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
       {
            {1, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {1, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        }
    },
    {
        {
            {1, 0, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {1, 1, 0, 0},
            {1, 0, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
       {
            {1, 1, 0, 0},
            {0, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {0, 1, 0, 0},
            {1, 1, 0, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        }
    },
    {
        {
            {1, 1, 0, 0},
            {0, 1, 1, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {0, 0, 1, 0},
            {0, 1, 1, 0},
            {0, 1, 0, 0},
            {0, 0, 0, 0}
        },
       {
            {1, 1, 0, 0},
            {0, 1, 1, 0},
            {0, 0, 0, 0},
            {0, 0, 0, 0}
        },
        {
            {0, 0, 1, 0},
            {0, 1, 1, 0},
            {0, 1, 0, 0},
            {0, 0, 0, 0}
        }
    }
};

有了方块之后,我们使用SDL2库对数组对应方块就行渲染,即值不为0的位置渲染出方块粒,值为0的位置不渲染。同时,我们使用颜色类型这个变量代表红、绿、蓝、黄色的方块,不同颜色使用不同的纹理。

void drawBlocks(TT_Window *win, TT_Block *block){
    if(block->bShown == false){
        return;
    }
    int i, j;
    int x = block->x;
    int y = block->y;
    for(i = 0; i < TT_BLOCK_NUM_AREA_HEIGHT; i++){
        x = block->x;
        for(j = 0; j < TT_BLOCK_NUM_AREA_WIDTH; j++){
            if(TT_Blocks[block->type][block->curTransState][i][j] >= 1){
                renderImageFromTexture(win, &block->tex[block->colorType - 1], NULL, x, y);
            }
            x += TT_BLOCK_WIDTH;
        }
        y += TT_BLOCK_HEIGHT;
    }
}

我们利用SDL2把不同图片载入成相应的的纹理(Texture),如红、黄、绿、蓝色方块粒的图片以及背景图片。

TT_Texture loadImageTexture(TT_Window *win, const char *imgPath){
    TT_Texture texture = {
        .texture = NULL,
        .width = 0,
        .height = 0
    };
    SDL_Surface *surface = IMG_Load(imgPath);
    if(!surface){
        SDL_Log("Failed to load image %s: %s\n", imgPath, IMG_GetError());
    }else{
        SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, 0xff, 0xff, 0xff));
        texture.texture = SDL_CreateTextureFromSurface(win->render, surface);
        if(!texture.texture){
            SDL_Log("Failed to load image %s: %s\n", imgPath, SDL_GetError());
        }
        texture.width = surface->w;
        texture.height = surface->h;
        SDL_FreeSurface(surface);
    }
    return texture;
}

再添加一些俄罗斯方块的游戏逻辑,如消除完成的层,统计得分等。

void deleteCompletedBlocks(TT_Block *block){
    if(block->remainBlockWidth < TT_BACKGROUND_WIDTH){
        return;
    }
    int width = 0;
    int height = 0;
    int rowFlag = 0;
    int tmp[TT_BLOCK_NUM_BACKGROUND_HEIGHT][TT_BLOCK_NUM_BACKGROUND_WIDTH];
    SDL_memset(tmp, 0, sizeof (tmp));
    for(int i = 0; i < TT_BLOCK_NUM_BACKGROUND_HEIGHT; i++){
        width = 0;
        for(int j = 0; j < TT_BLOCK_NUM_BACKGROUND_WIDTH; j++){
            if(TT_RemainBlocks[i][j] >= 1){
                width += 1;
                if(width == TT_BLOCK_NUM_BACKGROUND_WIDTH){
                    for(int k = 0; k < TT_BLOCK_NUM_BACKGROUND_WIDTH; k++){
                        TT_RemainBlocks[i][k] = 0;
                    }
                    block->score++;
                    if(block->score > block->maxScore){
                        block->maxScore = block->score;
                    }
                    playSound(block->completeSound);
                }
            }
        }
    }
    height = TT_BLOCK_NUM_BACKGROUND_HEIGHT - 1;
    for(int i = TT_BLOCK_NUM_BACKGROUND_HEIGHT - 1; i > 0; i--){
        for(int j = 0; j < TT_BLOCK_NUM_BACKGROUND_WIDTH; j++){
            if(TT_RemainBlocks[i][j] >= 1){
                tmp[height][j] = TT_RemainBlocks[i][j];
                rowFlag = 1;
            }
        }
        if(rowFlag == 1){
            --height;
            rowFlag = 0;
        }
    }
    SDL_memcpy(TT_RemainBlocks, tmp, sizeof (TT_RemainBlocks));

    calRemainBlocksSize(block);
}

我们来看看运行效果吧:

基于SDL2自制俄罗斯方块_第2张图片

 

项目地址:https://gitee.com/yorkee/tetris

你可能感兴趣的:(C)