游戏开发 mine

mine开发

1.前期准备

1.1工具:VC,easyx

基础知识:循环,数组,函数

1.2mine区地图绘制

我们做一个9行9列的二维数组,-1和0代表有mine和无mine
这个数组最好是全局,这样很多函数都可以访问得到(注意全局数组自动初始化为0)

需要的头文件和宏定义如下:

#include<stdio.h>
#include<graphics.h>
#define ROW 9//9行9列的mine区表格
#define COL 9
#define MINE_WID 40//图片宽度
int mine[ROW][COL];

1.3打印 printMap()函数

先做点简单的工作,写一个输出数组的函数,方便后面调用

void printMap()
{
    for(int i=0;i<ROW;i++)
    {
        for(int j=0;j<COL;j++)
        {
            printf("%3d",mine[i][j]); //格式控制一下,一个数字占3个
        }
        printf("\n");//每一行就输出一个换行
    }
}

main()调用一下

int main()
{
    printMap();
    return 0;
}
image-20210205180152573

资源文件有数字标记,空白格子,红旗,地图,以及mine,复制进入工程的当前目录

图片定义一个数组,作为全局变量,这个数组可被各个函数访问修改

IMAGE img[12];

1.4初始化

void gameInit()
{
    loadimage(&img[0],"./0.png",MINE_WID,MINE_WID);
    loadimage(&img[1],"./1.png",MINE_WID,MINE_WID);
    loadimage(&img[2],"./2.png",MINE_WID,MINE_WID);
    loadimage(&img[3],"./3.png",MINE_WID,MINE_WID);
//是不是没完没了?
}

比较繁琐,需要简化处理一下

//上面的代码要复制12次,我们用循环处理简化代码
void gameInit()
{
    char temp[20]=" "; 
    for(int i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//把路径+i吸入temp变量
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}

资源加载完了,我们开始绘制图片(贴图)

void gameDraw()
{
    for(int i=0;i<ROW;i++)
    {
        for(int j=0;j<COL;j++)
        {
            if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(i*MINE_WID,j*MINE_WID,&img[0]);
            }
        }
    }
}

现在主函数调用一下

int main()
{
    initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
    gameInit(); //资源初始化
    gameDraw();//绘制
    printMap();//控制台作为后台数据帮忙分析
    system("pause");//记得 #include<stdlib>
    
    return 0;
}
image-20210207121625293

1.5开始布mine

mine的数量做一个宏定义,方便后期修改

define MAX_MINE 9 //mine先少布置一点 方便分析

//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为mine区,并且要判断不要有 重合的下标
    int x,y;
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {
        //srand((unsigned int)time(0)); // 此语句要放在for 循环体之外
        //加上上一句srand函数,同时和#include<time.h>即为真随机,每次布mine不一样
        x=rand()%9;
        y=rand()%9;
        //判断是否重复
        if(mine[x][y]==0) //没有mine的情况下,就埋mine,有mine就没做这一步
        {
            mine[x][y]=-1;
            //当布mine成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个mine
        }
    }
    char temp[20]=" "; 
    for(int i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}

布mine之后运行看一下

image-20210209102851067

多次运行,发现真随机的mine区发生变化,由于我们在gameDraw()绘图函数里面只定义了当数值为0,没有mine的时候绘制空白砖块,所以当数值为-1的时候,需要绘制地mine

1.6绘制mine

//根据后台数据,给出绘制mine区定义
//为-1布mine,增加 if else if分支,记住还要有数字选项的分支,所以不要只写else
void gameDraw()
{
    for(int i=0;i<ROW;i++)
    {
        for(int j=0;j<COL;j++)
        {
            if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(i*MINE_WID,j*MINE_WID,&img[0]);
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(i*MINE_WID,j*MINE_WID,&img[9]); //新增一个else分支即可,mine是9.jgp,第10张图
            }
        }
    }
}
image-20210209103711589

对比一下数据,行列是颠倒的,将绘图函数里面新增两个变量,对应起来

void gameDraw()
{
    for(int i=0;i<ROW;i++)
    {
        for(int j=0;j<COL;j++)
        {
            int x=j*MINE_WID;
            int y=i*MINE_WID;
            if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[0]);
            }
            else
            {
                putimage(x,y,&img[9]); // 注意到 if else 后面会更新为 if else if,防止条件空间不完备
            }
        }
    }
}

1.7布mine的数字

现在mine区有了,那么一个数字代表周围有多少mine,那么有一个mine,周围数字全部+1

注意,数字进行累加,但是不要把自己也是mine区的数字-1也给变化了,在gameInit()里面进行更改

void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为mine区,并且要判断不要有 重合的下标
    int x,y;
    srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9;
        y=rand()%9;
        //判断是否重复
        if(mine[x][y]==0) //没有mine的情况下,就埋mine,有mine就没做了
        {
            mine[x][y]=-1;
            //当布mine成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个mine
        }
    }
    // 遍历数组,对mine九宫格进行+1操作
    for(int a=0;a<ROW;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=0;b<COL;b++)
        {
            //首先要找到是mine的i,j
            if(mine[a][b]==-1) //再嵌套一个二层循环
            {
                for(int k=a-1;k<=a+1;k++)
                {
                    for(int q=b-1;q<=b+1;q++)
                    {
                        //周围的遍历,只对非mine区进行操作
                        if(mine[k][q]!=-1)
                        {
                            mine[k][q]++;
                        }
                    }
                }
                
            }
        }
    }
    
    char temp[20]=" "; 
    for(int i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}
image-20210209105554555

尝试输出一下,程序可能会假死,可能不会,取决于编译器对数组上下限±1的严格程度,以及硬件反应速度。

问题出在哪里?思考一下!

1.8mine区在边界,-1,+1操作会越界,内存会溢出,访问不到!

小技巧:增加一个 ±1,作为辅助圈,在11*11格子里面的判断。
#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的mine区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2]; //辅助圈,在这里+2了
IMAGE img[12];
那么,0行,10行与0列,11列成为辅助圈

判断的数字增加的行列从a=1,到小于row+1(b=1到b<COL+1)

for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;b++)
        {
            //首先要找到是mine的i,j
            if(mine[a][b]==-1) //再嵌套一个二层循环
            {
                for(int k=a-1;k<=a+1;k++)
                {
                    for(int q=b-1;q<=b+1;q++)
                    {
                        //周围的遍历,只对非mine区进行操作
                        if(mine[k][q]!=-1)
                        {
                            mine[k][q]++;
                        }
                    }
                }
                
            }
        }
    }
image-20210209115651732

现在没有内存溢出的隐患了

我们先输出辅助区,printMap()里面的ROW、COL行列分别+2

void printMap()
{
    for(int i=0;i<ROW+2;i++) //更新辅助区  i,j循环变量最好是在最开始初始化,不要放在for循环体里随用随申请
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}
image-20210209120119516

但是辅助圈现在作为不越界访问帮忙计数,是不能布mine的

辅助圈可以有数字,但是不能有-1布mine,我们修改rand功能 从1到9布mine

       
//x=rand()%9//从0到8
//y=rand()%9//从0到8
        x=rand()%9+1; //产生从1到9
        y=rand()%9+1;
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]==0) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[0]);
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]); // 之前的if else更新为多分支链
            }
        }
    }
}

void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}

现在前后台就对应上了

image-20210209131907167

1.9数字绘制

然后根据数组里面的数字,填充mine区标记数字,在drawMap()函数里面修改一下

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]);
            }
        }
    }
}

运行调试多次,验证随机性,并观察数字与mine区是否对应正确

image-20210209132307371
image-20210209132449688

tips:这里我们更新一下,完整代码如下

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的mine区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
IMAGE img[12];

void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}
//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为mine区,并且要判断不要有 重合的下标
    int x,y,i,j;
    srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;
        y=rand()%9+1;
        //判断是否重复
        
        if(mine[x][y]==0) //没有mine的情况下,就埋mine,有mine就没做了
        {
            mine[x][y]=-1;
            //当布mine成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个mine
        }
        
    }
    // 遍历数组,对mine九宫格进行+1操作.
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;b++)
        {
            //首先要找到是mine的i,j
            if(mine[a][b]==-1) //再嵌套一个二层循环
            {
                for(int k=a-1;k<=a+1;k++)
                {
                    for(int q=b-1;q<=b+1;q++)
                    {
                        //周围的遍历,只对非mine区进行操作
                        if(mine[k][q]!=-1)
                        {
                            mine[k][q]++;
                        }
                    }
                }
                
            }
        }
    }



    
    
    char temp[20]=" "; 
    for( i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(i=1;i<ROW+1;i++) //遍历数据区域
    {
        for(j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]);
            }
        }
    }
}
 int main()
{
    initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
    gameInit(); //资源初始化
    gameDraw();//绘制
    printMap();//控制台作为后台数据帮忙分析
    system("pause");//记得 #include<stdlib>
    
    return 0;
}

2.游戏加密与交互操作

2.1加密

刚刚只是做好了数据系统,现在我们要做加密掩盖和交互,不然直接显示最终的结果了。

加密格子,把数组里面(数据区,不要包含辅助圈)每一个值+一个数,这里为20

for(i=1;i<=ROW;i++) //  i,j循环变量需要在前面定义
{
    for(j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}

我们更新一下gameInit()函数,如果编译器对临时下标i,j检查严格,就不要在for循环里面反复int i=0,重复使用下标也可以。

void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为mine区,并且要判断不要有 重合的下标
    int x,y,i,j;
    srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;
        y=rand()%9+1;
        //判断是否重复
        
        if(mine[x][y]==0) //没有mine的情况下,就埋mine,有mine就没做了
        {
            mine[x][y]=-1;
            //当布mine成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个mine
        }
        
    }
    // 遍历数组,对mine九宫格进行+1操作.
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;b++)
        {
            //首先要找到是mine的i,j
            if(mine[a][b]==-1) //再嵌套一个二层循环
            {
                for(int k=a-1;k<=a+1;k++)
                {
                    for(int q=b-1;q<=b+1;q++)
                    {
                        //周围的遍历,只对非mine区进行操作
                        if(mine[k][q]!=-1)
                        {
                            mine[k][q]++;
                        }
                    }
                }
                
            }
        }
    }

for(i=1;i<=ROW;i++)
{
    for(j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}



    
    
    char temp[20]=" "; 
    for(i=0;i<12;i++) //对于检查严格的编译器,临时变量可重复使用了,不要再int i=0
    {
        sprintf(temp,"%d.jpg",i);//
        loadimage(&img[i],temp,MINE_WID,MINE_WID);
        
    }
}

加密之后,数据区+20,图没有贴了,未加密前数据最小是-1,最大是8

+20之后,最小是19,最大是28,增加分支判断,在这个区域覆盖掩盖图片(这个图片可以仍然为空白,为了掩饰效果,我们换一个不一样的图)

image-20210209133324661

绘图函数更新

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]);
            }
            else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到19范围,+20之后在19到28贴掩盖图片
            {
                putimage(x,y,&img[10]); //贴掩盖图片

            }
        }
    }
}
image-20210209134100539

2.2鼠标操作

开头增加鼠标消息定义 MOUSEMSG msg;
任务:点击之后,加密后的数据解密(实现方法??)
点击之后,鼠标消息一般配合 无限循环反复贴图!

#include<stdio.h>
#include<graphics.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的mine区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
IMAGE img[12];
MOUSEMSG msg;
void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫mine有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
           //加密的格子进行减操作
            mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20;
            //这里的y和x对调,是因为横向是x,纵向是y,然后只绘制数据区
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN)
        {
            
        }
            
    }
    
            
}

现在我们在主函数调用试一下,要反复绘图,记得主函数中把点击操作与绘图操作放入死循环中

 int main()
{
    initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
    gameInit(); //资源初始化
    while(1)//死循环重复绘图
    
    {
        gameDraw();//绘制

        gameMouse();
    }
    printMap();//控制台作为后台数据帮忙分析
    system("pause");//记得 #include<stdlib>
    
    return 0;
}

image-20210209135154001

扫mine左键是做什么?
右键是做什么??

void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫mine有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
           //加密的格子进行减操作
            mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20;
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN)//判断右键点击进行标记
        {
            if( mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]<30) //简化处理,没有放置标记红旗的都是在小于30
            {
                 mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]+=20;//直接+20,让数字大于30,给放置红旗做准备(-1到8+了20,从19~28,大于30简化)

            }
            else //否则什么? 否则就是 大于30,有红旗了
            {
                 mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]-=20; //如果本来就有红旗,就-20,取消红旗标记
                 //注意在 gameDraw ()里面更新  else if(mine[i][j]>30) putimage(x,y,&img[11]);
            

            }
            
        }
            
    }
    
            
}

gameDraw()更新一下

void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]);
            }
            else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到19范围,+20之后在19到28贴掩盖图片
            {
                putimage(x,y,&img[10]);

            }
            else if(mine[i][j]>30)
            {
                putimage(x,y,&img[11]);
            }

        }
    }
}

调试一下,验证红旗标记,数字标记,mine区标记,与红旗标记,取消红旗标记功能

image-20210210094333553

2.3判断游戏结束与胜利

什么是输?
就是踩到mine了!踩mine之后,是点击事件发生,已经发生了数据解密,与-1进行比较,弹出一个窗口,弹出功能需要 在文件开头加入
HWND hwnd=NULL;

void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[msg.y/MINE_WID+1][msg.x/MINE_WID+1]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中mine了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
          exit(0);
       
       }
  }
           
}

现在我们调用一下

int main()
{
    initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
    gameInit(); //资源初始化
    printMap();//控制台作为后台数据帮忙分析
    while(1)
    
    {
        
        gameDraw();//绘制
        gameMouse();
        gameDraw();//绘制二次,弹出窗口
        gameWinorLose();
    }
    
    system("pause");//记得 #include<stdlib>
    
    return 0;
}

当然游戏还有更完善的功能,比如点击空白区域,全部展开,我们需要更新一下代码,将鼠标坐标作为全局坐标方便传递参数,将鼠标消息的坐标赋值给openx,openy,代码会更简洁

#include<stdio.h>
#include<graphics.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的mine区表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
int openx,openy;
IMAGE img[12];
MOUSEMSG msg;
HWND hwnd=NULL;
//全局变量方便访问,mine[openx][openy]更简洁一些
void gameMouse()
{
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫mine有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
        {
            openx=msg.y/MINE_WID+1;
            openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20; 
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN) //判断右键点击进行标记
        {
            if( mine[openx][openy]<30) //简化处理,没有放置标记红旗的都是在小于30
            {
                 mine[openx][openy]+=20;//直接+20,让数字大于30,给放置红旗做准备

            }
            else
            {
                 mine[openx][openy]-=20; //如果本来就有红旗,就-20,取消红旗标记
                 //注意在 drawMap()里面更新    else if(mine[i][j]>30) putimage(x,y,&img[11]);
            

            }
            
        }
            
    }
    
            
}
//同样这里可以简单的处理一下
void gameWinorLose()
{
    //复制一下鼠标消息的代码
  if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
       if(mine[openx][openy]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {
          MessageBox(hwnd,"中mine了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
          exit(0);
       
       }
  }
           
}

然后我们来设计打开空白全部展开的函数

void openNull(int x,int y) //传递openx,openy进来
{
    if(mine[x][y]==0)//如果是空白(已经解密了,对0进行操作)
    {
        for (int i=x-1;i<=x+1;i++)//二层遍历周围的方格子
        {
            for(int j=y-1;j<=y+1;j++)
            {
                if(mine[i][j]==20)//周围的格子没有点,没有解密,与20进行判断
                {
                    mine[i][j]-=20;//解密为空格0
                    openNull(i,j);//递归调用到周围所有的空格全部一键打开退出
                }
            }
        }
    }
    
    
}

openNull()函数,在鼠标消息的左键点击判断里面调用,这样就一次展开所有空格,部分代码如下

 if(msg.uMsg==WM_LBUTTONDOWN)
        {
            openx=msg.y/MINE_WID+1;
            openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20;
            openNull(openx,openy);//空白格子递归全展开
            
        }

3.结束完整代码(有兴趣的同学,可以加入胜利消息)

#include<stdio.h>
#include<graphics.h>
#include<Windows.h>
#include<stdlib.h>
#include<time.h>
#define ROW 9//9行9列的数据表格
#define COL 9
#define MINE_WID 40
#define MAX_MINE 9
int mine[ROW+2][COL+2];
int openx,openy;
IMAGE img[12];
MOUSEMSG msg;
HWND hwnd=NULL;


void printMap() //数组作为储存数据,把外圈也绘制出来
{
    for(int i=0;i<ROW+2;i++)
    {
        for(int j=0;j<COL+2;j++)
        {
            printf("%3d",mine[i][j]);
        }
        printf("\n");
    }
}
//在二维数组里面随机获取9个下标,赋值为-1
void gameInit()
{
    //随机化给下标为x,y的赋值为-1,标记为mine区,并且要判断不要有 重合的下标
    int x,y;
    srand((unsigned int)time(0));
    for(int m=0;m<MAX_MINE;)//注意m++的操作,不在这里
    {

        x=rand()%9+1;// 1-9 有9个格子
        y=rand()%9+1;
        //判断是否重复
        
        if(mine[x][y]==0) //没有mine的情况下,就埋mine,有mine就没做了
        {
            mine[x][y]=-1;
            //当布mine成功了,m才++
            m++;//放在判断这里++,才会保证一定布满9个mine
        }
        
    }
for(int a=1;a<ROW+1;a++) // VC6在cpp文件不能重复定义i,j。所以避开一下
    {
        for(int b=1;b<COL+1;b++)
        {
            //首先要找到是mine的i,j
            if(mine[a][b]==-1) //再嵌套一个二层循环
            {
                for(int k=a-1;k<=a+1;k++)
                {
                    for(int q=b-1;q<=b+1;q++)
                    {
                        //周围的遍历,只对非mine区进行操作
                        if(mine[k][q]!=-1)
                        {
                            mine[k][q]++;
                        }
                    }
                }
                
            }
        }
    }
for(int i=1;i<=ROW;i++)
{
    for(int j=1;j<=COL;j++)
    {
        mine[i][j]+=20;
    }
}


    
    
    char temp[20]=" "; 
    for(i=0;i<12;i++)
    {
        sprintf(temp,"%d.jpg",i);//
        //loadimage(&img[i],temp,MINE_WID,MINE_WID);
        loadimage(img+i,temp,MINE_WID,MINE_WID);
    
        
    }
}
//绘图是mine数组里面的 1行到9行,1列到9列
//根据后台数据,给出绘制mine区定义
//为-1布mine,增加 if else if分支,切忌还要有数字选项,所以不要只写else
//绘图是mine数组里面的 1行到9行,1列到9列
void gameDraw()
{
    for(int i=1;i<ROW+1;i++)
    {
        for(int j=1;j<COL+1;j++)
        {
            int x=(j-1)*MINE_WID;//同步更新下标
            int y=(i-1)*MINE_WID;
            if(mine[i][j]>=0&&mine[i][j]<=8) //初始化开始为0的时候,全部填充空白砖块
            {
                 putimage(x,y,&img[mine[i][j]]); //根据mine[i][j]的数字来绘制对应的图片,注意图片的文件名要与自己显示的东西相符合
            }
            else if(mine[i][j]==-1) //当为-1的时候布mine
            {
                putimage(x,y,&img[9]);
            }
             else if(mine[i][j]>=19&&mine[i][j]<=28) //所有的数字在-1到8范围,+20之后在19到28贴掩盖图片
            {
                putimage(x,y,&img[10]); //贴掩盖图片

            }
             else if(mine[i][j]>30) 
             {
                 putimage(x,y,&img[11]);
             }
        }
    }
}
void openNull(int x,int y);
//全局变量方便访问,mine[openx][openy]更简洁一些
void gameMouse()
{
    int rx,ry;
    if(MouseHit())
    {
        msg=GetMouseMsg(); //注意大小写
        //扫mine有标记功能,判断鼠标左右键。左键确定,右键标记为红旗
        if(msg.uMsg==WM_LBUTTONDOWN)
         {
            openx=msg.y/MINE_WID+1;
            openy=msg.x/MINE_WID+1;
           //加密的格子进行减操作
            mine[openx][openy]-=20;
            openNull(openx,openy);//空白格子递归全展开
            
        }
        else if(msg.uMsg==WM_RBUTTONDOWN) //判断右键点击进行标记
        { rx=msg.y/MINE_WID+1; //左键坐标因为有两个函数需要用到,openNull和GameMouse,右键只有红旗
         //防止死循环中先点击左键全局变量的干扰, 右键的坐标单独判断
            ry=msg.x/MINE_WID+1;
            
            if( mine[rx][ry]<30) //简化处理,没有放置标记红旗的都是在小于30
            {
                 mine[rx][ry]+=20;//直接+20,让数字大于30,给放置红旗做准备

            }
            else
            {
                 mine[rx][ry]-=20; //如果本来就有红旗,就-20,取消红旗标记
                 //注意在 drawMap()里面更新    else if(mine[i][j]>30) putimage(x,y,&img[11]);
            

            }
            
        }
            
    }
    
            
}
void openNull(int x,int y) //传递openx,openy进来
{
    if(mine[x][y]==0)//如果是空白(已经解密了,对0进行操作)
    {
        for (int i=x-1;i<=x+1;i++)//二层遍历周围的方格子
        {
            for(int j=y-1;j<=y+1;j++)
            {
                if(mine[i][j]==20)//周围的格子没有点,没有解密,与20进行判断
                {
                    mine[i][j]-=20;//解密为空格0
                    openNull(i,j);//递归调用到周围所有的空格全部一键打开退出
                }
            }
        }
    }
    
    
}
void gameWinorLose()
{
    //复制一下鼠标消息的代码

    gameMouse();
       
       if(mine[openx][openy]==-1) //注意点击之后的判断进行了解密操作,对-1进行判断,有时候是对加密后的数据进行判断,要自己学会区分
           //include加入对话框弹出结束游戏 #include<Windows.h>
       {

           gameDraw(); //踩mine之后再调用一次贴图,此处贴出mine的照片
          MessageBox(hwnd,"中mine了!","Game Over",MB_OK); 
           //全局变量区加入 HWND hwnd=NULL;
          exit(0);
       
       }
  
           
}

 int main()
{
    initgraph(MINE_WID*ROW,MINE_WID*COL,1); //参数 1,是同时绘图与打开控制台
    gameInit(); //资源初始化
    while(1)//死循环重复绘图
    
    {
        gameDraw();//绘制

        gameMouse(); 
        gameWinorLose();//调用顺序优化
    }
    printMap();//控制台作为后台数据帮忙分析
    system("pause");//记得 #include<stdlib>
    
    return 0;
}


报告要求:

1. 请分别对 99数据区cmd窗口, 伪随机贴图窗口,带辅助圈的1111数据区cmd窗口,真随机贴图窗口,游戏贴图数字1-8及mine的静态图,加密后鼠标左键功能的实现、加密后鼠标右键功能的实现、游戏失败提示弹出窗口进行截图 (递归清零不做要求)

2. 请总结函数定义、调用、及声明的基本方式

3. 请以伪代码的形式简要分析 布mine算法、mine数字标记扫描算法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容