#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