admin 管理员组文章数量: 1184232
前言
每日鸡汤
不为模糊不清的未来过分担忧,只为清清楚楚的现在奋发图强。
基本思路
衔接基础班扫雷
如果思路不是特别清晰的兄弟,建议多看一下基础版扫雷:
如果EasyX图形库不是特别明白:可以看一下这篇文章:
或者B站我自己找的教程:
这一篇与上一章的部分思路相同:放置雷与初始化雷盘,不过由于我们的游戏界面为图形化界面我们的雷盘只需设置一个存放信息(雷和雷周围的信息),而且放雷的时候可以直接将雷的信息放在雷的周围更加方便,由于存放信息的雷盘只有一个,因此我们设置整形的数组会更加方便一些!
准备阶段
所需图片:
感谢
风雨封笙提出的问题:这里少了一些图片,我把源码链接放出来供给大家参考, 。
防止字符集出现问题:
#define_CRT_SECURE_NO_WARNINGS1#defineROWS11//行#defineCOLS11//列#defineCOL(ROWS-2)//打印的列,括号是为了防止运算冲突4#defineROW(COLS-2)//打印的行#defineMINE10#include<graphics.h>//要包含在SIZE的前面,防止与里面的SIZE冲突。EasyX要用#defineSIZE50#include<stdio.h>#include<time.h>//time函数的头文件,c++只能用这个#include<stdlib.h>//srand和rand函数的头文件,c++只能用这个#include<mmsystem.h>//播放音乐所用的头文件,是系统自带的#pragmacomment(lib,"winmm.lib")//加载静态库//初始化函数voidInitboard(int board[ROWS][COLS],int rows,int cols,int m);//打印函数voidPrintboard(int board[ROWS][COLS],int row,int col);//设置雷的函数voidSetmine(int board[ROWS][COLS],int row,int col);//加载图片的函数voidloadimages();//放图片的函数voidputimages(int board[ROWS][COLS],int row,int col);//加密的函数voidpassword(int board[ROWS][COLS],int rows,int cols);//鼠标信息的函数voidmouseimages(int board[ROWS][COLS]);//判断输赢的函数voidjudge(int mine[ROWS][COLS]);正文
说明:我们先在实现的逻辑的源文件实现函数的功能,,最后我们再把功能汇总一下,这样逻辑比较顺。
一.雷盘信息的存储
1.设置雷盘11*11与初始化
作用:防止在排查雷时,数组越界。
说明:数组已经初始化,下面只是初始化雷盘的函数。
代码:
//这里四个参数的功能与基础篇相同voidInitboard(int board[ROWS][COLS],int rows,int cols,int m){int i =0;int j =0;for(i =0; i < rows; i++){for(j =0; j < cols; j++){
board[i][j]=0;}}}2.放置雷
注意:
1.在.cpp后缀的文件中引用time函数时只能用time.h
2.在.cpp后缀的文件中引用srand函数和rand函数时只能用stdlib.h
说明:下面的代码的随机数起点已经在项目开始时建立,下面是设置雷的函数
代码:
voidSetmine(int board[ROWS][COLS],int row,int col){int count =0;while(count<MINE){//随机坐标//横坐标,行int x =rand()%9+1;//1——9//纵坐标,列int y =rand()%9+1;if(board[x][y]==0){
board[x][y]=-1;//在雷的周围加1,下面的放置雷周围的信息会有说明mine_information(board,x,y);
count++;}}}3.放置雷周围的信息
图解:
//放置static的目的是将外部链接属性改为内部链接属性,使此函数只能在实现逻辑的//源文件中进行使用,更为安全。staticvoidmine_information(int board[ROWS][COLS],int x,int y){int i =0;int j =0;for(i = x -1; i <= x +1; i++){for(j = y -1; j <= y +1; j++){if(i != x || j != y)//i与j不能同时为x和y{
board[i][j]+=1;}}}}二.图形化界面
1.创建与初始化窗口
在main函数里面创建
intmain(){//创建一个9*50(宽),10*50(高),并且展示控制台窗口。initgraph((ROW)* SIZE,(COL+1)* SIZE, SHOWCONSOLE);//游戏的逻辑省去了,最后接上去getchar();closegraph();
retuen 0;}2.加载图片
我们先把所需的图片加载之后才能进行使用,否则使用不了。
代码:
voidloadimages(){char fill[50]="";int i =0;for(i =0; i <12; i++){sprintf(fill,"./扫雷/%d.jpg", i);loadimage(&image[i], fill,SIZE,SIZE);//设置50*50的大小}loadimage(&image[12],"./扫雷/12.jpg",SIZE*ROW,SIZE);//设置450*50的大小}3.放入图片
如何放呢?
前九行放雷信息的图片,最后一行放雷的个数的图片。
尤其注意:行和列与横坐标和纵坐标的关系,将行和列转化成界面的纵坐标和横坐标,再放进去。
voidputimages(int board[ROWS][COLS],int row,int col){putimage(0, ROW * SIZE,&image[12]);int i =0;int j =0;for(i =1; i <= row; i++){//行为纵坐标for(j =1; j <= col; j++){//列为横坐标int n = board[i][j];//方便书写if(n ==-1){putimage((j -1)* SIZE,(i -1)* SIZE,&image[9]);}elseif(n >=0&& n <=8){putimage((j -1)* SIZE,(i -1)* SIZE,&image[n]);}//加密之后elseif(n >=19&& n <=28){putimage((j -1)* SIZE,(i -1)* SIZE,&image[10]);//加密格子}elseif(n >=39&& n <=48){putimage((j -1)* SIZE,(i -1)* SIZE,&image[11]);//标记}}}}4.加密格子
将格子加上20之后就将格子加密了,当你点击时,这个格子所对应的数组的元素减去二十,再把原来的图片(这个位置存储的信息)放上去即可。
代码:
voidpassword(int board[ROWS][COLS],int rows,int cols){//将所有格子都加上20int i =0;int j =0;for(i =0; i < rows; i++){for(j =0; j < cols; j++){
board[i][j]+=20;}}}三.鼠标点击
1.具体步骤
1.获取鼠标信息
2.将鼠标信息转化为数组下标
3.将鼠标信息进行分发
4.将情况分类进行解密与加密
2.代码实现
voidmouseimages(int board[ROWS][COLS]){if(MouseHit()){
MOUSEMSG msg =GetMouseMsg();//列对应横坐标int col = msg.x / SIZE +1;//行对应纵坐标int row = msg.y / SIZE +1;int m = board[row][col];switch(msg.uMsg)//分发鼠标信息{case WM_LBUTTONDOWN:if(m >=19&& m <=48)//只有在这个范围才执行操作,否则会将这个格子弄没{
board[row][col]-=20;}//递归展开省略了break;case WM_RBUTTONDOWN:if(m >=19&& m <=28){
board[row][col]+=20;}break;}}}四.递归展开
1.具体步骤
1.在为空格时,将周围的格子打开,且不为自身
2.打开的格子是加密的
3.加密的格子不是雷
4.如果为空继续调用
2.代码实现
staticvoidNullarround(int board[ROWS][COLS],int x,int y){if(board[x][y]==0)//判断是否为空白{int i =0;int j =0;for(i = x -1; i <= x +1; i++){for(j = y -1; j <= y +1; j++){if(i != x || j != y){if(board[i][j]!=19&& board[i][j]>=9)//比没加密大就是加密的格子,且加密的格子不为雷{
board[i][j]-=20;Nullarround(board, i, j);//继续调用,为空格继续展开。}}}}}}五.判断输赢
1.具体步骤
每次打开后都要判断一下,递归展开中也是。说明,这里如果输了或赢了,我们设置一个标志为flag为0,如果每次点击不为雷,那就加一,输了就设置为-1。
在赢或输之后我们就提示一下,是否要继续再开一把。
2.代码实现
voidjudge(int mine[ROWS][COLS]){if(flag ==-1){//失败int isok =MessageBox(GetHWnd(),"很遗憾!你输了!是否再来一把?","提示", MB_OKCANCEL);if(isok == IDOK){
flag =0;//将游戏初始化,意思就是再开一把Initboard(mine, ROWS, ROWS,0);Setmine(mine, ROW, COL);password(mine, ROWS, ROWS);}else{exit(5201314);//参数为随机数,退出程序。}}if(flag == ROW * COL - MINE){//胜利int isok =MessageBox(GetHWnd(),"很高兴!你赢了!是否再来一把?","提示", MB_OKCANCEL);if(isok == IDOK){
flag =0;//将游戏初始化Initboard(mine, ROWS, ROWS,0);Setmine(mine, ROW, COL);password(mine, ROWS, ROWS);}else{exit(5201314);//随机数}}}六.设置音乐与点击音效
入门EasyX的教程里面都有细说,如果不明白可以看一下教程,就在文章开头,点击即可进入。
1.播放音乐
代码:
//初始化界面时要打开音乐mciSendString("open ./扫雷/卡农.mp3",0,0,0);//打开音乐后要播放音乐mciSendString("play ./扫雷/卡农.mp3 repeat",0,0,0);//游戏结束后要关闭音乐mciSendString("close ./扫雷/卡农.mp3 repeat",0,0,0);2.播放音效
说明:每次点击要播放,播放完或者下一次播放时关闭,要不然只会响一次。
mciSendString("close ./扫雷/点击声音.wav",0,0,0);mciSendString("open ./扫雷/点击声音.wav",0,0,0);mciSendString("play ./扫雷/点击声音.wav",0,0,0);七.总结代码
1.运行逻辑的代码:mine.cpp
#define_CRT_SECURE_NO_WARNINGS1#include"mine.h"int flag =0;intmain(){initgraph((ROW)* SIZE,(COL+1)* SIZE, SHOWCONSOLE);setbkcolor(WHITE);cleardevice();srand((unsignedint)time(NULL));int mine[ROWS][COLS]={0};Initboard(mine, ROWS, ROWS,0);Setmine(mine,ROW,COL);password(mine, ROWS, ROWS);Printboard(mine, ROW, COL);mciSendString("open ./扫雷/卡农.mp3",0,0,0);mciSendString("play ./扫雷/卡农.mp3 repeat",0,0,0);loadimages();//每次放图片,鼠标点击,与判断是否结束是循环。while(1){BeginBatchDraw();//批量开始绘图使图形更加的稳定putimages(mine, ROW, COL);FlushBatchDraw();//批量结束绘图使图形更加的稳定mouseimages(mine);judge(mine);//Printboard(mine, ROW, COL);}int ret =getchar();closegraph();}2.头文件代码:mine.h
#define_CRT_SECURE_NO_WARNINGS1#defineROWS11#defineCOLS11#defineCOL(ROWS-2)#defineROW(COLS-2)#defineMINE10#include<graphics.h>//要包含在SIZE的前面,防止与里面的SIZE冲突。#defineSIZE50#include<stdio.h>#include<time.h>#include<stdlib.h>#include<mmsystem.h>#pragmacomment(lib,"winmm.lib")voidInitboard(int board[ROWS][COLS],int rows,int cols,int m);voidPrintboard(int board[ROWS][COLS],int row,int col);voidSetmine(int board[ROWS][COLS],int row,int col);voidloadimages();voidputimages(int board[ROWS][COLS],int row,int col);voidpassword(int board[ROWS][COLS],int rows,int cols);voidmouseimages(int board[ROWS][COLS]);voidjudge(int mine[ROWS][COLS]);3.实现逻辑的代码:源.cpp
#define_CRT_SECURE_NO_WARNINGS1#include"mine.h"
IMAGE image[13];externint flag;staticvoidNullarround(int board[ROWS][COLS],int x,int y){if(board[x][y]==0)//判断是否为空白{int i =0;int j =0;for(i = x -1; i <= x +1; i++){for(j = y -1; j <= y +1; j++){if(i != x || j != y){if(board[i][j]!=19&& board[i][j]>=9)//比没加密大就是加密的格子{
board[i][j]-=20;
flag++;Nullarround(board, i, j);//继续调用,为空格继续展开。}}}}}}staticvoidmine_information(int board[ROWS][COLS],int x,int y){int i =0;int j =0;for(i = x -1; i <= x +1; i++){for(j = y -1; j <= y +1; j++){if((i != x || j !=y)&&board[i][j]!=-1){
board[i][j]+=1;}}}}voidInitboard(int board[ROWS][COLS],int rows,int cols,int m){int i =0;int j =0;for(i =0; i < rows; i++){for(j =0; j < cols; j++){
board[i][j]=0;}}}voidPrintboard(int board[ROWS][COLS],int row,int col){system("cls");int i =0;int j =0;for(i =1; i <= row; i++){for(j =1; j <= col; j++){printf("%2d ",board[i][j]);}printf("\n");}}voidSetmine(int board[ROWS][COLS],int row,int col){int count = MINE;while(count){//随机坐标//横坐标,行int x =rand()%9+1;//1——9//纵坐标,列int y =rand()%9+1;if(board[x][y]==0){
board[x][y]=-1;//在雷的周围加1mine_information(board,x,y);
count--;}}}voidloadimages(){char fill[50]="";int i =0;for(i =0; i <12; i++){sprintf(fill,"./扫雷/%d.jpg", i);loadimage(&image[i], fill,SIZE,SIZE);}loadimage(&image[12],"./扫雷/12.png",SIZE*ROW,SIZE);}voidputimages(int board[ROWS][COLS],int row,int col){putimage(0, ROW * SIZE,&image[12]);int i =0;int j =0;for(i =1; i <= row; i++){//行为纵坐标for(j =1; j <= col; j++){//列为横坐标int n = board[i][j];if(n ==-1){putimage((j -1)* SIZE,(i -1)* SIZE,&image[9]);}elseif(n >=0&& n <=8){putimage((j -1)* SIZE,(i -1)* SIZE,&image[n]);}//加密之后elseif(n >=19&& n <=28){putimage((j -1)* SIZE,(i -1)* SIZE,&image[10]);//加密格子}elseif(n >=39&& n <=48){putimage((j -1)* SIZE,(i -1)* SIZE,&image[11]);//标记}}}}//加密voidpassword(int board[ROWS][COLS],int rows,int cols){//将所有格子都加上20int i =0;int j =0;for(i =0; i < rows; i++){for(j =0; j < cols; j++){
board[i][j]+=20;}}}voidmouseimages(int board[ROWS][COLS]){if(MouseHit()){
MOUSEMSG msg =GetMouseMsg();//列对应横坐标int col = msg.x / SIZE +1;//行对应纵坐标int row = msg.y / SIZE +1;int m = board[row][col];switch(msg.uMsg)//分发鼠标信息{case WM_LBUTTONDOWN:if(m >=19&& m <=48){mciSendString("close ./扫雷/点击声音.wav",0,0,0);mciSendString("open ./扫雷/点击声音.wav",0,0,0);mciSendString("play ./扫雷/点击声音.wav",0,0,0);
board[row][col]-=20;if(board[row][col]!=-1){
flag++;}else{
flag =-1;break;}}//递归展开Nullarround(board, row, col);break;case WM_RBUTTONDOWN:if(m >=19&& m <=28){
board[row][col]+=20;}break;}}}voidjudge(int mine[ROWS][COLS]){if(flag ==-1){//失败int isok =MessageBox(GetHWnd(),"很遗憾!你输了!是否再来一把?","提示", MB_OKCANCEL);if(isok == IDOK){
flag =0;//将游戏初始化Initboard(mine, ROWS, ROWS,0);Setmine(mine, ROW, COL);password(mine, ROWS, ROWS);}else{mciSendString("close ./扫雷/卡农.mp3",0,0,0);exit(5201314);//随机数}}if(flag == ROW * COL - MINE){//胜利int isok =MessageBox(GetHWnd(),"很高兴!你赢了!是否再来一把?","提示", MB_OKCANCEL);if(isok == IDOK){
flag =0;//将游戏初始化Initboard(mine, ROWS, ROWS,0);Setmine(mine, ROW, COL);password(mine, ROWS, ROWS);}else{mciSendString("close ./扫雷/卡农.mp3",0,0,0);exit(5201314);//随机数}}}
效果:
总结
如果能认真看到这里,我坚信你能收获很多很多!也希望这篇文章能帮助到你,如果觉得不错,请点击一下不要钱的赞,如果有误请温柔的指出,在这里感谢大家了!
版权声明:本文标题:C语言编程实战:扫雷游戏的进阶挑战,带你走进递归算法与用户互动设计的世界 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/p/1771178182a3541667.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论