扫雷游戏制作过程

一、创作工具 

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*)强转为intif (!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-8for (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,最大为28else 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*)强转为intif (!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-8for (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,最大为28else 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;
}

六、运行结果预览

生成游戏

点击空白格子,递归打开周围空白格子和数字

点击到雷,游戏结束,失败

标记出所有雷,游戏胜利

C/C++ 扫雷游戏制作相关推荐

  1. 扫雷游戏制作学习过程

    1. 扫雷游戏的构思:   设计为初级,中级,高级三个级别. 因此不妨设置为如下规格: 9x9 16x15和30x16 (行,列)规格不同地雷的数量也不同,分别为 10,40 ,99 2.在这个过程遇 ...

  2. python扫雷游戏课程设计小组任务计划与分配表_Python开源扫雷游戏由网瘾少年制作,转手后月入18K,附赠所有源文件...

    原标题:Python开源扫雷游戏由网瘾少年制作,转手后月入18K,附赠所有源文件 最近入手一款Python扫雷游戏,迫不及待的打开源文件试玩几次之后,颇感惭愧-惭愧这么经典的游戏居然不是由我这种&qu ...

  3. 制作Java小游戏~扫雷游戏

    上大学之前没必要去花钱培训哈.四年的时间足够自学了 可以参考我一下的建议: 看一些视频和书籍,注意你需要把基础打好.现在小破站上等很多第三方网站上有免费的,其实质量很不错的我把我自己整理的一些比较好的 ...

  4. 使用Tableau制作扫雷游戏和三维地图

    一种利用低代码可视化工具处理复杂逻辑的有益尝试. 可视化作品的复杂度无外乎两种: 模型处理层的复杂度 和 可视化设计层的复杂度 模型处理层的复杂度 当计算逻辑异常复杂,无法直接通过线性计算获取计算结果 ...

  5. 用js制作一个扫雷游戏(vue版)

    使用js来制作一个扫雷游戏,可以分为以下几个步骤 1.根据不同难度构建扫雷游戏区域: 2.在游戏区域中放置地雷: 3.处理点击事件: 4.处理游戏结束事件 1.根据不同难度构建扫雷游戏区域 创建一个二 ...

  6. java制作扫雷游戏中埋雷的难点_Java 实现经典扫雷游戏

    最后一次更新于 2019/07/08 效果演示图 Java 实现经典扫雷游戏 本扫雷游戏有以下功能: 如果点中炸弹会显示炸弹. 玩家左键点击方块能显示该方块周围会出现几个炸弹,如果不存在炸弹的话扫描范 ...

  7. 用纯JavaScript制作扫雷游戏-2

    网页扫雷游戏 - part 2

  8. 小心踩雷!手把手教你制作扫雷游戏简单版本

    扫雷游戏----C语言必写游戏之一 扫雷游戏 背景 起源与玩法 基本实现思路 涉及语言的主要内容 具体实现步骤 1.基本框架 2.菜单页面的实现 3.初始化棋盘 4.在屏幕中显示棋盘 5.布置好棋盘中 ...

  9. c++ 制作低配扫雷游戏

    c++写的一个低配扫雷游戏. #include <iostream> #include <stdlib.h> #include <windows.h> #inclu ...

最新文章

  1. 每个程序员都应该学习使用Python或Ruby
  2. 配置 postCSS 自动添加 css 的兼容前缀||打包样式表中的图片和字体文件||打包处理 js 文件中的高级语法
  3. 佳能2020转印带拆卸图解_RF人文街拍小钢炮 佳能RF35mm F1.8 MACRO IS STM
  4. Java NIO:Buffer、Channel 和 Selector
  5. 细说Linux 系统优化
  6. 微型计算机技术及应用 考试,陕西理工学院微型计算机技术及应用考试试卷(5份)...
  7. SSM中(Spring-SpringMVC-Mybatis)(二:整合)
  8. 输入6个学生的5门成绩c语言数组,C语言数组指针的小例子.pdf
  9. ORACLE自增长字段实现(转)
  10. 想成为嵌入式程序员应知道的0x10个基本问题——转
  11. PHP程序员必须收藏的资源大全
  12. final关键字多态
  13. 最齐全的装饰贴图素材,速来收藏
  14. 烟雾检测传感器实验-传感器原理及应用实验
  15. 《About Multi-Touch(多点触摸是个什么东西?)》:Sony PS3Eye 介绍、拆解与使用全指南...
  16. win10桌面计算机打不开,win10开机后桌面无响应,win10开机后啥都打不开
  17. java protobuf extend_protobuf中extension的使用
  18. 怎么使用计算机公式,如何在电脑上输入运算公式?
  19. 农业科普:智慧果园种植科研(二)
  20. 海康IPCamera结合OpenCV图像处理的一般步骤

热门文章

  1. ExtJs 常用代码片段(7.30更新)
  2. Android 控件描边只描一边
  3. magento focalprice 模板去掉 in xxx的分类
  4. CentOS Out of Memery问题分析
  5. unity串口 连接多个串口崩溃_什么是串口服务器 和串口转以太网模块有什么区别...
  6. 罗斯蒙特3051严格要求过程参数控制精度性能优异
  7. 嘿嘿嘿,你还不知道呢?软件测试自学网站
  8. html+ol+从+开始,从零开始的全栈工程师——html篇1.5
  9. 监控264后缀文件播放
  10. 福州物联网开放实验室与CPChain技术提供方物融智能达成战略合作