程序非常复杂,转载供大神评论
#include <time.h>
#include <stdlib.h>
#include "codingtang.h"
#define TITLE "Mine Cweeper" //定义游戏名称
#define QUAD 32 //一张图片的长宽像素
#define QORG 64
#define XSIZE 20 // x尺寸 20张图片
#define YSIZE 20 // y尺寸
#define WIDTH XSIZE*QUAD // 屏幕 宽
#define HEIGHT YSIZE*QUAD // 屏幕 高
#define CELLS_NUM XSIZE*YSIZE // 扫雷块的最大数量 20*20
#define BOMB_MAX CELLS_NUM/10 // 炸弹的最大数量,为总块数的十分之一 400/10
#define BOMB 9 // 炸弹编号为9
#define WALL 10 // 未点击图片编号为10
#define MARK 11 // 旗子标记编号为11
typedef struct{
int img;
bool bomb;
int adj;
bool check;
} Cell;
//定义扫雷块结构体,每扫雷块有:
// img(照片编号) bomb(是否是炸弹) adj(九宫格内有几个炸弹) check(是否点击)
Window window;
// 创建窗口
void setupGame(const char *text, Cell cells[], int x, int y); //初始化游戏
int coin(int min, int max); // 随机数
void render(const char *text, int offset, int x, int y); //渲染单个
void renderAll(const char *text, Cell cells[]); // 渲染全部内容
int checkCell(Cell cells[],int x, int y); //点击
bool click(Cell cells[], int x, int y ); //是否点击
bool mark(Cell *cell, int *marked, int *disc); //是否标记
void addAdj(Cell cells[], int x, int y); // 检测周围炸弹数量
void setBombs(Cell cells[],int bombs,int x, int y); //设置炸弹数量
void setupGame(const char *text, Cell cells[], int x, int y) {
window.clear(); //清空窗口
for(int i = 0; i < XSIZE; i++) { //遍历整个屏幕 20*20
for(int j = 0; j < YSIZE; j++) {
cells[i+j*XSIZE].img = WALL; //默认为未点击状态
cells[i+j*XSIZE].bomb = false;//默认非炸弹
cells[i+j*XSIZE].adj = 0; //默认周围无炸弹
cells[i+j*XSIZE].check = false; //默认为未点击
render(text,WALL,i,j); //这个图片渲染为10:未点击状态
}
}
setBombs(cells,BOMB_MAX,x,y); //设置炸弹
window.present(); //显示在窗口上面
}
int coin(int min, int max) {
int offset = rand() % (max-min);
return min+offset;
} //随机值在 min~max中间
void render(const char *text, int offset, int x, int y) { //渲染函数
SDL_Rect srcR; //原图的尺寸
SDL_Rect destR; //目标的区域
srcR.x = offset*QORG; //原图中第offset的区域
srcR.y = 0;
srcR.w = QORG; //原图尺寸
srcR.h = QORG; //原图尺寸
destR.x = x*QUAD; //目标图的区域选取
destR.y = y*QUAD; //目标图的区域选取
destR.w = QUAD; //目标图尺寸
destR.h = QUAD; //目标图尺寸
window.drawImageExt(text, srcR, destR); //绘制这个图片
}
void renderAll(const char *text, Cell cells[]) { //渲染全部函数
window.clear(); //清屏
for(int i = 0; i < XSIZE; i++) { //遍历整个屏幕 20*20
for(int j = 0; j < YSIZE; j++) {
render(text, cells[i+XSIZE*j].img,i,j); //将每张图片渲染出对应的位置
}
}
window.present(); //在窗口上面显示出来
}
bool mark(Cell *cell, int *marked, int *disc) { //标记切换
switch(cell->img) { // 判断这个扫雷块的图片
case MARK: { //如果是标记的就取消标记
cell->img = WALL;
*marked -= 1; //标记为0 :取消标记
break;
}
case WALL: { //如果是未标记 就切换为标记
if(*marked >= BOMB_MAX) break; //标记数量超过炸弹数,无法继续标记
cell->img = MARK; //否则就设置为标记
*marked+=1; //标记为1 : 状态:标记
if(cell->bomb) { //如果这个是炸弹:标记正确
*disc+=1; //标记正确的数量加1
}
return true; //标记成功
break;
}
}
return false; //否则标记失败
}
int checkCell(Cell cells[], int x, int y) { //点击扫雷块
int result = 0;
Cell *cell = &cells[x+y*XSIZE]; //选取对应的扫雷块
if(cell->check) return 0; //如果点击过,就结束
cell->img = cell->adj; // 设置图片为周围炸弹数量
cell->check = true; //设置为点击
result++;
if(cell->adj == 0) { //如果周围没有炸弹,就查找九宫格之内的其他方块
int downX = x-1;
int upX = x+1;
int downY = y-1;
int upY = y+1;
for(int i=downX;i<=upX;i++) {
for(int j=downY;j<=upY;j++) {
if( (i>=0) && (j>=0) && (i<XSIZE) && (j<YSIZE) ) {
result+=checkCell(cells,i,j);
}
}
}
}
return result; //返回最后的结果:点击数量
}
bool click(Cell cells[], int x, int y) { //能否点击
Cell *cell = &cells[x+y*XSIZE]; //选取对应的扫雷块
if(cell->bomb) { //如果是炸弹
cell->img = BOMB; //图片设置为炸弹
cell->check=true; //点击
return false; //不能点击
}
return true; //可以点击
}
void addAdj(Cell cells[], int x, int y) { //查找周围有几个炸弹
int downX = x-1;
if(downX<0) downX = 0;
int downY = y-1;
if(downY<0) downY = 0;
int upX = x+1;
if(upX >= XSIZE) upX = XSIZE-1;
int upY = y+1;
if(upY >= YSIZE) upY = YSIZE-1;
//选取九宫格,排除边缘情况
for(int i=downX; i<=upX; i++) {
for(int j=downY; j<=upY; j++) {
cells[i+j*XSIZE].adj++; //添加炸弹数量
}
}
}
//如果这个是炸弹,那么这个炸弹的九宫格其他块的炸弹数量都应该加1
void setBombs(Cell cells[], int bombs,int x, int y) { //设置炸弹
for(int i=0; i < bombs; i++) { //循环随机设置炸弹
int x0 = coin(0,XSIZE);
int y0 = coin(0,YSIZE);
if(cells[x0+y0*XSIZE].bomb) { //如果本身就是炸弹,会重新选择一个地方
i--;
}
else {
if(x != x0 || y != y0) {
cells[x0+y0*XSIZE].bomb = true; //设置为炸弹
addAdj(cells,x0,y0); //添加炸弹周围其他块的adj
}
}
}
}
int main(int argc, char** argv)
{
srand(time(NULL)); //随机数
window = createWindow(WIDTH, HEIGHT); //创建窗口
Cell cells[CELLS_NUM]; //定义扫雷块数组
string sprites = "bomb.png"; //设置精灵图
setupGame(sprites.c_str(),cells,0,0); //初始化游戏
SDL_Event event; //定义事件
Event ev; //定义ev事件
bool running = true; //游戏正在运行
bool lost = false; //游戏没有结束
int undisc = CELLS_NUM; //全部都是未知的 开始未点击
int marked = 0; //标记的数量
int disc = 0; //已知数量 (已经点击数量)
bool init = false; // 初始化
while(running) { //游戏运行中
if (waitEventTimeout(&ev, 250)){ //键盘事件监听
switch(ev.type) { //判断事件是什么类型
case CDT_QUIT: //退出事件
running = false; //游戏结束
break;
case CDT_KEY_DOWN:{ //按键按下事件
int keyCode = ev.keyCode; //定义一个按键
switch (keyCode){ //判断是什么按键按下
case CDT_KEY_ESCAPE: { //escape键 退出
running = false; //结束游戏
break;
}
case CDT_KEY_n: { //n键 重新开始游戏
setupGame(sprites.c_str(),cells,0,0);
undisc = CELLS_NUM;
}
}
}
case CDT_MOUSEBUTTONDOWN: { //鼠标按下事件
MouseButtonEvent button = ev.button; //定义一个鼠标按钮
int x = button.x/QUAD; //根据点击的坐标求得点击的区域
int y = button.y/QUAD;
if(!init) { //如果未初始化
setupGame(sprites.c_str(),cells,x,y); //初始化一下
undisc = CELLS_NUM;
marked = 0;
disc = 0;
init = true;
}
if(button.button == CDT_BUTTON_LEFT){ //如果是鼠标左键点击
lost = !click(cells,x,y); // 如果不能点击,就代表结束
if(lost) { //如果游戏结束
print("%s\n", "Game Over!"); //输出游戏结束
for(int i=0;i<XSIZE;i++) {
for(int j=0;j<YSIZE;j++) {
Cell *cell = &cells[i+j*XSIZE]; //选取对应的扫雷块
if(cell->bomb) { //如果是炸弹
cell->img = BOMB; //设置图片为炸弹
}
}
}
renderAll(sprites.c_str(),cells); //渲染全部
SDL_Delay(4000); //延时 4000毫秒
setupGame(sprites.c_str(),cells,0,0); //重置
undisc = CELLS_NUM;
marked = 0;
disc = 0;
init = false;
}
else {
undisc -= checkCell(cells,x,y); //点击之后的数量
if(undisc == BOMB_MAX) { //如果未点击的数量等于炸弹数
print("%s\n", "You won!"); //胜利
renderAll(sprites.c_str(),cells); //渲染全部
SDL_Delay(2000); //延迟2000毫秒
setupGame(sprites.c_str(),cells,0,0); //重置游戏
undisc = CELLS_NUM;
marked = 0;
disc = 0;
init = false;
}
}
}
else if(button.button == CDT_BUTTON_RIGHT) { //如果是鼠标右键点击
if(mark(&cells[x+y*XSIZE], &marked, &disc)) { //标记函数
if(disc == BOMB_MAX) { //如果标记数量等于炸弹数。获胜
print("%s\n", "You won!");
renderAll(sprites.c_str(),cells); //重置
SDL_Delay(2000);
setupGame(sprites.c_str(),cells,0,0);
undisc = CELLS_NUM;
marked = 0;
disc = 0;
init = false;
}
}
}
renderAll(sprites.c_str(),cells); //点击操作完成后,渲染全部
}
}
}
}
window.quit(); //退出窗口
return 0;
}