首页 > 其他分享 >简单的SDL扫雷游戏

简单的SDL扫雷游戏

时间:2024-09-09 22:51:14浏览次数:12  
标签:20 游戏 int WIDTH 扫雷 renderer SDL board

#include <SDL.h>
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <string>
#undef main  // 解除宏定义,防止与main函数冲突

// 常量定义
const int WIDTH = 9;  // 游戏板的宽度(格子数)
const int HEIGHT = 9; // 游戏板的高度(格子数)
const int MINES = 10; // 地雷的数量
const int CELL_SIZE = 32; // 每个格子的大小(像素)
const int WINDOW_WIDTH = WIDTH * CELL_SIZE; // 窗口的宽度
const int WINDOW_HEIGHT = HEIGHT * CELL_SIZE; // 窗口的高度

// 结构体定义,表示一个格子的状态
struct Cell {
    bool mine;           // 是否有地雷
    bool revealed;       // 是否被揭露
    int minesAround;     // 周围的地雷数量
};

// 函数声明
void initBoard(Cell board[HEIGHT][WIDTH], int mines); // 初始化游戏板
void drawBoard(SDL_Renderer* renderer, Cell board[HEIGHT][WIDTH]); // 绘制游戏板
void handleEvents(SDL_Event& e, Cell board[HEIGHT][WIDTH]); // 处理事件
bool isMine(Cell board[HEIGHT][WIDTH], int x, int y); // 判断某位置是否有地雷
void countMines(Cell board[HEIGHT][WIDTH]); // 计算每个格子周围的地雷数量
int countAround(Cell board[HEIGHT][WIDTH], int x, int y); // 计算特定格子周围的地雷数量
bool gameWon(Cell board[HEIGHT][WIDTH]); // 判断游戏是否胜利
bool allNonMinesRevealed(Cell board[HEIGHT][WIDTH]); // 判断所有非地雷格子是否都被揭露
void drawNumber(SDL_Renderer* renderer, int num, int x, int y); // 绘制数字
void drawDigit(SDL_Renderer* renderer, int digit, int x, int y, SDL_Color color); // 绘制单个数字

int main(int argc, char* argv[]) {
    if (SDL_Init(SDL_INIT_VIDEO) < 0) { // 初始化SDL
        std::cerr << "SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;
        return 1;
    }

    SDL_Window* window = SDL_CreateWindow( // 创建窗口
        "Mine Sweeper",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        WINDOW_WIDTH,
        WINDOW_HEIGHT,
        SDL_WINDOW_SHOWN
    );

    if (!window) { // 检查窗口创建是否成功
        std::cerr << "Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;
        SDL_Quit();
        return 1;
    }

    SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); // 创建渲染器
    if (!renderer) { // 检查渲染器创建是否成功
        std::cerr << "Renderer could not be created! SDL_Error: " << SDL_GetError() << std::endl;
        SDL_DestroyWindow(window);
        SDL_Quit();
        return 1;
    }

    Cell board[HEIGHT][WIDTH]; // 定义游戏板
    initBoard(board, MINES); // 初始化游戏板

    bool running = true; // 控制主循环运行标志
    SDL_Event e; // 事件对象

    while (running) { // 主循环
        while (SDL_PollEvent(&e)) { // 检测事件
            handleEvents(e, board); // 处理事件
            if (e.type == SDL_QUIT) { // 如果是退出事件
                running = false; // 停止主循环
            }
        }

        drawBoard(renderer, board); // 绘制游戏板

        if (gameWon(board)) { // 如果游戏胜利
            std::cout << "You won!" << std::endl;
            running = false; // 停止主循环
        }

        SDL_RenderPresent(renderer); // 更新屏幕
    }

    SDL_DestroyRenderer(renderer); // 销毁渲染器
    SDL_DestroyWindow(window); // 销毁窗口
    SDL_Quit(); // 卸载SDL

    return 0;
}

// 初始化游戏板
void initBoard(Cell board[HEIGHT][WIDTH], int mines) {
    int i, j, k = 0;

    // 设置所有格子为未揭示且无地雷状态
    for (i = 0; i < HEIGHT; ++i)
        for (j = 0; j < WIDTH; ++j) {
            board[i][j].mine = false;
            board[i][j].revealed = false;
            board[i][j].minesAround = 0;
        }

    // 随机放置地雷
    while (k < mines) {
        int x = rand() % WIDTH;
        int y = rand() % HEIGHT;
        if (!board[y][x].mine) {
            board[y][x].mine = true;
            ++k;
        }
    }
    countMines(board); // 计算每个格子周围的地雷数量
}

// 计算每个格子周围的地雷数量
void countMines(Cell board[HEIGHT][WIDTH]) {
    for (int i = 0; i < HEIGHT; ++i)
        for (int j = 0; j < WIDTH; ++j)
            if (!board[i][j].mine)
                board[i][j].minesAround = countAround(board, i, j);
}

// 计算特定格子周围的地雷数量
int countAround(Cell board[HEIGHT][WIDTH], int x, int y) {
    int count = 0;
    for (int dx = -1; dx <= 1; dx++)
        for (int dy = -1; dy <= 1; dy++) {
            if (dx == 0 && dy == 0) continue; // 不计算自身
            int nx = x + dx;
            int ny = y + dy;
            if (nx >= 0 && nx < HEIGHT && ny >= 0 && ny < WIDTH && board[nx][ny].mine)
                count++; // 如果周围有地雷,计数加一
        }
    return count;
}

// 判断某位置是否有地雷
bool isMine(Cell board[HEIGHT][WIDTH], int x, int y) {
    return board[y][x].mine;
}

// 绘制游戏板
void drawBoard(SDL_Renderer* renderer, Cell board[HEIGHT][WIDTH]) {
    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); // 设置背景颜色
    SDL_RenderClear(renderer); // 清除渲染目标

    // 循环遍历每个格子
    for (int i = 0; i < HEIGHT; ++i)
        for (int j = 0; j < WIDTH; ++j) {
            SDL_Rect rect = { j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE }; // 计算格子位置
            if (board[i][j].revealed) { // 如果格子已揭示
                SDL_SetRenderDrawColor(renderer, 192, 192, 192, 255); // 设置格子颜色
                if (board[i][j].mine) { // 如果是地雷
                    SDL_RenderFillRect(renderer, &rect); // 绘制地雷格子
                    // 可以在这里添加一个地雷的图像来表示地雷
                }
                else { // 如果不是地雷
                    SDL_RenderFillRect(renderer, &rect); // 绘制非地雷格子
                    if (board[i][j].minesAround > 0) { // 如果周围有地雷
                        drawNumber(renderer, board[i][j].minesAround, rect.x + 5, rect.y + 5); // 绘制地雷数量
                    }
                }
            }
            else { // 如果格子未揭示
                SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255); // 设置格子颜色
                SDL_RenderFillRect(renderer, &rect); // 绘制未揭示格子
            }
        }
}

// 绘制数字
void drawNumber(SDL_Renderer* renderer, int num, int x, int y) {
    std::string text = std::to_string(num); // 将数字转换成字符串
    for (size_t i = 0; i < text.length(); ++i) { // 遍历字符串中的每个字符
        drawDigit(renderer, text[i] - '0', x, y, { 0, 0, 0 }); // 绘制单个数字
        x += 20; // 假设每个数字宽度为20
    }
}

// 绘制单个数字
void drawDigit(SDL_Renderer* renderer, int digit, int x, int y, SDL_Color color) {
    SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255); // 设置颜色
    switch (digit) { // 根据数字绘制不同形状
    case 1:
        SDL_RenderDrawLine(renderer, x, y, x + 20, y + 20); // 数字1
        SDL_RenderDrawLine(renderer, x, y + 20, x + 20, y);
        break;
    case 2:
        SDL_RenderDrawLine(renderer, x, y, x + 20, y); // 数字2
        SDL_RenderDrawLine(renderer, x + 20, y, x + 20, y + 20);
        SDL_RenderDrawLine(renderer, x + 20, y + 20, x, y + 20);
        SDL_RenderDrawLine(renderer, x, y + 20, x, y);
        break;
    case 3:
        SDL_RenderDrawLine(renderer, x, y, x + 20, y); // 数字3
        SDL_RenderDrawLine(renderer, x + 20, y, x + 20, y + 10);
        SDL_RenderDrawLine(renderer, x + 20, y + 10, x, y + 10);
        SDL_RenderDrawLine(renderer, x, y + 10, x, y + 20);
        SDL_RenderDrawLine(renderer, x, y + 20, x + 20, y + 20);
        break;
        // 其他数字类似
    default:
        break;
    }
}

// 处理事件
void handleEvents(SDL_Event& e, Cell board[HEIGHT][WIDTH]) {
    if (e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) { // 左键点击
        int x, y;
        SDL_GetMouseState(&x, &y); // 获取鼠标位置
        int col = x / CELL_SIZE; // 计算点击的列
        int row = y / CELL_SIZE; // 计算点击的行
        if (col >= 0 && col < WIDTH && row >= 0 && row < HEIGHT) { // 如果点击在有效范围内
            board[row][col].revealed = true; // 揭示该格子
            if (isMine(board, col, row)) { // 如果该格子是地雷
                std::cout << "Game Over!" << std::endl;
                exit(0); // 结束程序
            }
        }
    }
}

// 判断游戏是否胜利
bool gameWon(Cell board[HEIGHT][WIDTH]) {
    return allNonMinesRevealed(board); // 调用辅助函数判断
}

// 判断所有非地雷格子是否都被揭露
bool allNonMinesRevealed(Cell board[HEIGHT][WIDTH]) {
    int nonMineCells = 0; // 非地雷格子计数器
    for (int i = 0; i < HEIGHT; ++i)
        for (int j = 0; j < WIDTH; ++j)
            if (!board[i][j].mine && board[i][j].revealed)
                nonMineCells++; // 如果是非地雷且已揭露,计数加一

    return nonMineCells == (HEIGHT * WIDTH - MINES); // 如果非地雷格子数等于总数减去地雷数,则胜利
}

标签:20,游戏,int,WIDTH,扫雷,renderer,SDL,board
From: https://blog.csdn.net/2401_82456630/article/details/142071457

相关文章

  • C语言中数组的知识(后面有三子棋小游戏)
    一、数组的创建和初始化    数组是一组同类型元素的集合,合理运用数组可以帮我们完成一些复杂的操作    1.1一维数组的创建和初始化    一维数组创建的方式:type_tarr_name[const_n];//type_t是指数组的元素类型//const_n是一个常量表达式,用......
  • 博弈论 Nim游戏
        本文参考链接:https://www.geeksforgeeks.org/combinatorial-game-theory-set-2-game-nim/给定许多堆,其中每堆包含一些数量的石头。在每一回合中,玩家只能选择一堆并从该堆中移除任意数量的石子(至少一个)。无法移动的玩家被视为输掉游戏(即,拿走最后一颗石头的玩家获胜   ......
  • 《星球大战:亡命之徒》游戏启动时崩溃弹窗“缺少kernel32.dll”该怎么解决?星球大战亡命
    当《星球大战:亡命之徒》启动时崩溃弹窗提示“缺少kernel32.dll”,可以尝试重新安装游戏,看是否能恢复该文件。也可从可靠渠道下载kernel32.dll,放置到系统目录下,以解决问题让游戏正常启动。本篇将为大家带来《星球大战:亡命之徒》游戏启动时崩溃弹窗“缺少kernel32.dll”该怎么解决......
  • 《黑神话:悟空》游戏启动时崩溃弹窗“找不到amdvlk64.dll”该怎么办?黑神话悟空游戏闪退
    当《黑神话:悟空》启动时崩溃弹窗提示“找不到amdvlk64.dll”,可以考虑重新安装游戏以找回该文件。也可从可靠来源下载amdvlk64.dll,放置到游戏安装目录下,尝试解决问题让游戏正常启动。本篇将为大家带来《黑神话:悟空》游戏启动时崩溃弹窗“找不到amdvlk64.dll”该怎么办的内容,感兴......
  • 【小项目】python贪吃蛇小游戏设计
    引入pygame库添加pygame库,在cmd中输入以下代码,进行安装。如果输入pipinstallpygame出现以下报错,可以尝试在前面加入python3-m。python3-mpipinstallpygame贪吃蛇代码importpygameimporttimeimportrandom#初始化Pygamepygame.init()#定义颜色white=......
  • 《黑神话》的狂欢,开拓出国产游戏行业的一片蓝海
    《黑神话》的狂欢,开拓出国产游戏行业的一片蓝海自8月20日《黑神话:悟空》发售以来,国内外游戏圈从未停止过对于这款现象级国产3A游戏的讨论,这种讨论的声势愈发浩大,乃至各路与游戏并不相关的主流媒体也纷纷下场站台,为其发出鼓励与支持的声音。相比起前些年,电子游戏在主流媒体......
  • 电脑怎么录屏幕视频带声音?游戏、微课录制必看!
    在数字化时代,无论是游戏爱好者想要分享精彩瞬间,还是教育工作者需要制作微课视频,掌握电脑屏幕录制并同步声音的技能都变得尤为重要。今天,我们就来揭秘几种高效且易用的录屏方法,需要的朋友快快码住!1.嗨格式录屏大师——专业级录制体验获取地址:录屏大师软件免费下载_高清电......
  • ‌游戏被IP限制了怎么办:‌全面解析原因与应对策略
    在数字化娱乐盛行的今天,‌网络游戏已成为许多人生活中不可或缺的一部分。‌然而,‌有时玩家可能会遇到游戏被IP限制的问题,‌这无疑给游戏体验带来了不便。‌本文将深入探讨游戏被IP限制的原因,‌并提供一系列有效的解决方法,‌希望帮助玩家重新获得游戏访问权限,‌畅享无忧的游戏时......
  • 游戏录屏掉帧怎么办?有什么录屏软件推荐吗?
    对于广大游戏爱好者来说,录制游戏精彩瞬间、分享攻略或制作教程已经成为一种常态。然而,在录屏过程中,不少玩家都会遇到掉帧的问题,这不仅影响了视频的流畅度,也大大降低了观看体验。那么,面对游戏录屏掉帧的困扰,我们该如何解决?又有哪些录屏软件值得推荐呢?下面就一起来看看吧。一......
  • 专为游戏行业设计的安全防护盾——游戏盾
    游戏行业可以说是近年来发展最为迅猛的行业之一了,在数字化的浪潮下游戏行业成为互联网娱乐的重要支柱。然而繁荣的行业发展背后隐藏着越来越严峻的网络安全挑战,尤其是DDoS攻击、CC攻击等恶意行为频发。为了应对复杂的网络环境,快快网络推出针对游戏行业打造的高定制网络安全解决......