基于SDL2自制俄罗斯方块

本文介绍如何使用SDL2库自制俄罗斯方块游戏,包括定义不同种类的方块、使用纹理渲染方块、游戏逻辑实现等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

现在我们基于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);
}

我们来看看运行效果吧:

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值