赞
踩
扫雷游戏制作过程
1、visual studio 2022
2、easyx图形库
1、图片
2、背景音乐
整合在一个文件夹里,与源文件放在一起,重命名方便操作
1、设置雷(-1)代表雷,空白格子为0,数字[0-8](雷周围整体加一,可叠加)雷周围数字出现情况:1—8
运用二维数组知识
静态数组int map[ ](不能改变)
动态数组int **map = malloc(10,sizeof(int):
生成的数组中每一个格子装了一个int*的指针
for(int i =0;i<10;i++)
{
map[i] = malloc(10,sizeof(int);
}
以此完成动态数组的申请;优势:可以随时扩容
2、利用easyx图形库函数创建一个窗口,创建一个存储图片数组,将准备好的图片放入指定位置(利用坐标实现)
3、排雷:
鼠标左击消除对应小格,右击标记(可用别的按键实现)
4、判定输赢条件
点到地雷,游戏结束;所有地雷被红旗标记,获得胜利,游戏结束
头文件设置,宏观设置
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
- #include<easyx.h>//图形库
- //动态数组分配需要用到的头文件
- #include<mmsystem.h>//添加音乐用到的头文件
- #pragma comment(lib,"winmm.lib")//取消警告(库文件)
- #define SIZE 20//设置图片尺寸大小
- #define num 100//设置雷的数量
- //加载资源,图片
- IMAGE imgs[12];//存储图片数组
加载填充图片
- void loadpng()
- {
- for (int i = 0;i < 12;i++)
- {
- char buf[50] = { 0 };
- sprintf(buf,"./photos/%d.png", i);//使得下面的图片也能跟着变换,注意要用到spintf完成
- //用sprintf时1.项目2.c/c++3.常规4.SDL检查5.选择否,软件问题可以去掉
- loadimage(imgs + i, buf, SIZE, SIZE);//用这个加图片时,1.项目2.属性3.高级4.字符集5.选则使用多节字符集
- }
-
- };
初始化Map,内存申请
- struct Map
- {
- int** arr;//二维数组指针
- int rows;//行数
- int cols;//列数
- };
- void map_init(Map* map, int rows, int cols)
- {
- map->rows = rows;
- map->cols = cols;
- map->arr = (int**)calloc(map->rows,sizeof(int*));//calloc是malloc的兄弟函数
- if (!map->arr)
- {
- printf("内存申请失败\n");
- return;
- }
- for (int i = 0;i < map->rows;i++)
- {
- map->arr[i] = (int*)calloc(map->cols, sizeof(int));//(int*)强转为int
- if (!map->arr[i])
- {
- printf("内存申请失败");//一般来说必须返回确认是否成功
- return;
- }
- }
- }
设置雷(-1)
- //设置雷 -1表示在0处随机设置-1形成雷
- void map_setMine(Map* map)
- {
- //设置随机数种子
- srand(time(NULL));//时间头文件
- for (int i = 0;i < num;)
- {
- //随机产生下标[0-10]
- int r = rand() % map->rows;
- int c = rand() % map->cols;
- if (map->arr[r][c] == 0)
- {
- map->arr[r][c] = -1;//雷设置完成,注意:此过程可能会使-1位置重复,
- //导致设置雷小于指定数,解决方法:加循环
- i++; //从for里把i++拿出来表示只有成功设置雷,才自增
- }
-
- }
- //把以雷为中心的九宫格的数字都加一(雷除外)形成数字0-8
- for (int i = 0; i < map->rows; i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- if (map->arr[i][k] == -1)
- {
- //以雷为中心的九宫格
- for (int r = i-1; r <= i+1; r++)
- {
- for (int c = k-1; c <= k+1; c++)
- {
- //排除掉雷
- if ((r >= 0 && r < map->rows && c >= 0 && c < map->cols)
- && map->arr[r][c] != -1)//此时加入边界判断即可恢复代码中断问题
- {
- map->arr[r][c] += 1;//此时代码有问题,可能会导致代码运行中断,
- //因为会越界(雷在边界),九宫格出现行超出列超出的情况
- }
- }
- }
- }
- }
- }
- }
输出一下所有数组,用于观察纠错,修正,
添加排查操作,用于检测标记方格是否为雷,如果排查标记出所有雷,则胜利,游戏结束
- //输出一下所有数组
- void map_show(Map* map)
- {
- int cir=0;//设置变量
- for (int i = 0;i < map->rows;i++)
- {
- for (int k = 0;k < map->cols;k++)
- {
- printf(" %2d ", map->arr[i][k]);
- if (map->arr[i][k] == 59)//判断标记的红旗是否为雷
- {
- cir += 1;
- if (cir == num)//如果排查出雷的数量与设置雷的数量一致则胜利
- {
- {
- WinWindow();//输出成功窗口,游戏结束
- getchar();
- }
- }
- }
- printf("\n\n");
- }
- }
覆盖起来,进行加密操作,将(-1—8)数字加20变为(19—28)进行加密
- //覆盖起来,加密操作
- void map_cover(Map* map)
- {
- //让现在数组里的数据变得不一样
- for (int i = 0; i < map->rows; i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- map->arr[i][k] += 20;
- }
- }
- }
绘制界面,图形窗口
- //绘制界面(图形窗口)
- void map_draw(Map* map)
- {
- for (int i = 0;i < map->rows;i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- //求每个格子的坐标
- int x = k * SIZE;
- int y = i * SIZE;
- if (map->arr[i][k] >= 0 && map->arr[i][k] <= 8)
- {
- putimage(x, y, imgs + map->arr[i][k]);//放置图片
- }
- else if (map->arr[i][k] == -1)
- {
- putimage(x, y, imgs + 11);//防置雷的图片
- }//加密后最小为19,最大为28
- else if (map->arr[i][k] >= 19 && map->arr[i][k] <= 28)
- {
- putimage(x, y, imgs + 9);//放置蓝色格子
- }
- else if (map->arr[i][k] >= 59 && map->arr[i][k] <= 68)
- {
- putimage(x, y, imgs + 10);//插旗标记
- }
- if (map->arr[i][k] == -1)
- {
- DieWindow();//点到雷了,生成游戏结束窗口,游戏结束
- getchar();//防止闪屏
- }
-
- }
-
- }
- }
左击格子打开与右击格子标记插旗,二次加密
- void map_mouseMsg(Map* map, ExMessage* msg)//消息参数,用鼠标需要的参数
- {
- //根据鼠标坐标,获得点击的格子的下标
- int r = msg->y / SIZE;
- int c = msg->x / SIZE;
- //判断鼠标左键是否点击
- if (msg->message == WM_LBUTTONDOWN&& map->arr[r][c] >= 19 && map->arr[r][c] <= 68)
- {
- if (map->arr[r][c] != 59)
- {
- map->arr[r][c] -= 20;//左击减数字,消除加密;
- map_recOpen(map, r, c);
- system("cls");
- map_show(map);//换进来不需要取地址&
- }
- }
- //判断是否为右键点击
- if (msg->message == WM_RBUTTONDOWN && map->arr[r][c] >= 19 && map->arr[r][c] <= 28)
- {
-
- map->arr[r][c] += 40;//右键标记雷,插旗子二次加密
- map_recOpen(map, r, c);
- system("cls");
- map_show(map);//换进来不需要取地址&
-
- }
-
- }
用递归法实现:若点击为空白格子则打开周围所有空白格子和数字
- //如果点到空白格子,递归打开周围的所有的空白格子和数字格子
- void map_recOpen(Map* map,int row,int col)
- {
- //先判断一下是否为空白格子
- if (map->arr[row][col] != 0)
- {
- return;
- }
- //延申到以空白格子为中心的九宫格
- for (int r = row - 1; r <= row + 1; r++)
- {
- for (int c = col - 1; c <= col + 1; c++)
- {
- if ((r >= 0 && r < map->rows && c >= 0 && c < map->cols)
- &&map->arr[r][c]>=19&&map->arr[r][c]<=28)
- {
- map->arr[r][c] -= 20;
- map_recOpen(map, r, c);//递归,自己调用自己
- }
- }
- }
- }
绘制游戏失败窗口,要用到easyx图形库
- void DieWindow()
- {
- BeginBatchDraw();//双缓冲绘图
- initgraph(400, 400);
- setbkmode(TRANSPARENT);
- settextcolor(LIGHTBLUE);
- outtextxy(150, 150, "BOOM!BOOM!");
-
- outtextxy(150, 120, "GameOver");
- EndBatchDraw();
- }
绘制游戏胜利窗口
- void WinWindow()
- {
- BeginBatchDraw();//双缓冲绘图
- initgraph(400, 400);
- setbkmode(TRANSPARENT);
- settextcolor(LIGHTBLUE);
- outtextxy(150, 150, "WOW!COOL!");
- outtextxy(150, 120, "恭喜你通关了");
- EndBatchDraw();
- }
主函数
- int main()
- {
- //创建图形窗口
- initgraph(800, 600,EW_SHOWCONSOLE);//长,宽,显示控制台
- //播放背景音乐
- mciSendString("open ./photos/trip.mp3 alias bgm", NULL, 0, NULL);
- mciSendString("play bgm repeat", NULL, 0, NULL);//循环播放
- loadpng();
- Map map;
- map_init(&map,30,40);//行,列
- map_setMine(&map);//&取地址
- map_cover(&map);
- //消息循环
- while (true)
- {
- ExMessage msg = {0};
- while (peekmessage(&msg, EM_MOUSE))
- {
- map_mouseMsg(&map, &msg);
- //map_show(&map);
- map_draw(&map);
- //WinGame(&map,m,n);
- }//用while循环因为括号内消息为真则继续循环
- }
- getchar();
- return 0;
- }
注意函数调用问题和逻辑问题
- #include<stdio.h>
- #include<stdlib.h>
- #include<time.h>
- #include<easyx.h>//图形库
- //动态数组分配需要用到的头文件
- #include<mmsystem.h>//添加音乐用到的头文件
- #pragma comment(lib,"winmm.lib")//取消警告(库文件)
- #define SIZE 20//图片尺寸
- #define num 10//雷的数量
- //加载资源,图片
- IMAGE imgs[12];//存储图片数组
-
- void loadpng()
- {
- for (int i = 0;i < 12;i++)
- {
- char buf[50] = { 0 };
- sprintf(buf,"./photos/%d.png", i);//使得下面的图片也能跟着变换,注意要用到spintf完成
- //用sprintf时1.项目2.c/c++3.常规4.SDL检查5.选择否,软件问题可以去掉
- loadimage(imgs + i, buf, SIZE, SIZE);//用这个加图片时,1.项目2.属性3.高级4.字符集5.选则使用多节字符集
- }
- };
- struct Map
- {
- int** arr;//二维数组指针
- int rows;//行数
- int cols;//列数
- };
- void map_recOpen(Map* map, int row, int col);
- void DieWindow();
- void WinWindow();
- //初始化MAP
- void map_init(Map* map, int rows, int cols)
- {
- map->rows = rows;
- map->cols = cols;
- map->arr = (int**)calloc(map->rows,sizeof(int*));//calloc是malloc的兄弟函数
- if (!map->arr)
- {
- printf("内存申请失败\n");
- return;
- }
- for (int i = 0;i < map->rows;i++)
- {
- map->arr[i] = (int*)calloc(map->cols, sizeof(int));//(int*)强转为int
- if (!map->arr[i])
- {
- printf("内存申请失败");//一般来说必须返回确认是否成功
- return;
- }
- }
- }
- //输出一下所有数组
- void map_show(Map* map)
- {
- int cir=0;
- for (int i = 0;i < map->rows;i++)
- {
- for (int k = 0;k < map->cols;k++)
- {
- printf(" %2d ", map->arr[i][k]);
- if (map->arr[i][k] == 59)
- {
- cir += 1;
- if (cir == num)
- {
- WinWindow();
- getchar();
- }
- }
- }
- printf("\n\n");
- }
- }
- //设置雷 -1表示在0处随机设置-1形成雷
- void map_setMine(Map* map)
- {
- //设置随机数种子
- srand(time(NULL));//时间头文件
- for (int i = 0;i < num;)
- {
- //随机产生下标[0-10]
- int r = rand() % map->rows;
- int c = rand() % map->cols;
- if (map->arr[r][c] == 0)
- {
- map->arr[r][c] = -1;//雷设置完成,但是这样会使=1位置重复,导致小于10个,方法:加循环
- i++;//从for里把i++拿出来表示只有成功设置雷,才自增
- }
- }
- //把以雷为中心的九宫格的数字都加一(雷除外)形成数字0-8
- for (int i = 0; i < map->rows; i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- if (map->arr[i][k] == -1)
- {
- //以雷为中心的九宫格
- for (int r = i-1; r <= i+1; r++)
- {
- for (int c = k-1; c <= k+1; c++)
- {
- //排除掉雷
- if ((r >= 0 && r < map->rows && c >= 0 && c < map->cols)
- && map->arr[r][c] != -1)//此时加入边界判断即可恢复代码中断问题
- {
- map->arr[r][c] += 1;//此时代码有问题,可能会导致代码运行中断,因为会越界(雷在边界),九宫格出现行超出列超出的情况
- }
- }
- }
- }
- }
- }
- }
- //绘制界面(图形窗口)
- void map_draw(Map* map)
- {
- for (int i = 0;i < map->rows;i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- //求每个格子的坐标
- int x = k * SIZE;
- int y = i * SIZE;
- if (map->arr[i][k] >= 0 && map->arr[i][k] <= 8)
- {
- putimage(x, y, imgs + map->arr[i][k]);
- }
- else if (map->arr[i][k] == -1)
- {
- putimage(x, y, imgs + 11);
- }//加密后最小为19,最大为28
- else if (map->arr[i][k] >= 19 && map->arr[i][k] <= 28)
- {
- putimage(x, y, imgs + 9);
- }
- else if (map->arr[i][k] >= 59 && map->arr[i][k] <= 68)
- {
-
- putimage(x, y, imgs + 10);
- }
- if (map->arr[i][k] == -1)
- {
- DieWindow();
- getchar();
- }
- }
- }
- }
- //覆盖起来,加密操作
- void map_cover(Map* map)
- {
- //让现在数组里的数据变得不一样
- for (int i = 0; i < map->rows; i++)
- {
- for (int k = 0; k < map->cols; k++)
- {
- map->arr[i][k] += 20;
- }
- }
- }
-
- //点击格子打开
- void map_mouseMsg(Map* map, ExMessage* msg)//消息参数,用鼠标需要的参数
- {
- //根据鼠标坐标,获得点击的格子的下标
- int r = msg->y / SIZE;
- int c = msg->x / SIZE;
- //判断鼠标左键是否点击
- if (msg->message == WM_LBUTTONDOWN&& map->arr[r][c] >= 19 && map->arr[r][c] <= 68)
- {
- if (map->arr[r][c] != 59)
- {
- map->arr[r][c] -= 20;//左击减数字,消除加密;
- map_recOpen(map, r, c);
- system("cls");
- map_show(map);//换进来不需要取地址&
- }
- }
- //判断是否为右键点击
- if (msg->message == WM_RBUTTONDOWN && map->arr[r][c] >= 19 && map->arr[r][c] <= 28)
- {
-
- map->arr[r][c] += 40;//右键标记雷,插旗子二次加密
- map_recOpen(map, r, c);
- system("cls");
- map_show(map);//换进来不需要取地址&
- }
- }
- //如果点到空白格子,递归打开周围的所有的空白格子和数字格子
- void map_recOpen(Map* map,int row,int col)
- {
- //先判断一下是否为空白格子
- if (map->arr[row][col] != 0)
- {
- return;
- }
- //遍历空白格子为中心的九宫格
- for (int r = row - 1; r <= row + 1; r++)
- {
- for (int c = col - 1; c <= col + 1; c++)
- {
- if ((r >= 0 && r < map->rows && c >= 0 && c < map->cols)
- &&map->arr[r][c]>=19&&map->arr[r][c]<=28)
- {
- map->arr[r][c] -= 20;
- map_recOpen(map, r, c);//递归,自己调用自己
- }
- }
- }
- }
-
- void DieWindow()
- {
- BeginBatchDraw();//双缓冲绘图
- initgraph(400, 400);
- setbkmode(TRANSPARENT);
- settextcolor(LIGHTBLUE);
- outtextxy(150, 150, "BOOM!BOOM!");
- outtextxy(150, 120, "GameOver");
- EndBatchDraw();
- }
- void WinWindow()
- {
- BeginBatchDraw();//双缓冲绘图
- initgraph(400, 400);
- setbkmode(TRANSPARENT);
- settextcolor(LIGHTBLUE);
- outtextxy(150, 150, "WOW!COOL!");
- outtextxy(150, 120, "恭喜你通关了");
- EndBatchDraw();
- }
- int main()
- {
- //创建图形窗口
- initgraph(800, 600,EW_SHOWCONSOLE);//长,宽,显示控制台
-
- //播放背景音乐
- mciSendString("open ./photos/trip.mp3 alias bgm", NULL, 0, NULL);
- mciSendString("play bgm repeat", NULL, 0, NULL);//循环播放
- loadpng();
- Map map;
- map_init(&map,30,40);//行列
- map_setMine(&map);//&取地址
- map_cover(&map);
- //消息循环
- while (true)
- {
- ExMessage msg = {0};
- while (peekmessage(&msg, EM_MOUSE))
- {
- map_mouseMsg(&map, &msg);
- //map_show(&map);
- map_draw(&map);
- //WinGame(&map,m,n);
- }//用while循环因为括号内消息为真则继续循环
- }
- getchar();
- return 0;
- }
生成游戏
点击空白格子,递归打开周围空白格子和数字
点击到雷,游戏结束,失败
标记出所有雷,游戏胜利
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。