赞
踩
目录
要实现扫雷,我们可以将其分为这样几个不同的部分来一一实现:
在扫雷中我们需要用到EasyX绘图库中包含的部分功能
附上官网链接:https://easyx.cn/
下面列出需要包含的头文件:
- #include<iostream>
- #include<cstdlib>
- #include<ctime>
- #include<graphics.h>
- #include<windows.h>
- #include<Mmsystem.h>
- #pragma comment(lib,"winmm.lib")
初始化需要用到的图片以及声音资源(我的资源是从别的博主那里下载来的,就是一二三四五和红旗的等,故不附上):
- int o = 0;
- int init[row + 2][col + 2];
- IMAGE img[11];
- void load()
- {
- loadimage(&img[0], L"0.jpg", size, size);
- loadimage(&img[1], L"1.jpg", size, size);
- loadimage(&img[2], L"2.jpg", size, size);
- loadimage(&img[3], L"3.jpg", size, size);
- loadimage(&img[4], L"4.jpg", size, size);
- loadimage(&img[5], L"5.jpg", size, size);
- loadimage(&img[6], L"6.jpg", size, size);
- loadimage(&img[7], L"7.jpg", size, size);
- loadimage(&img[8], L"8.jpg", size, size);
- loadimage(&img[9], L"9.jpg", size * row, size * col);
- loadimage(&img[10], L"10.jpg", size * row, size * col);
- }
- #define row 10 //定义行数
- #define col 10 //定义列数
- #define boom 10 //定义炸弹数
- #define size 50 //定义图片长宽
- int init[row + 2][col + 2];
- void InitGame()//初始化游戏、
- {
- for (int i = 0; i < row + 2; i++) //设置缓冲区,并使缓冲区内全为0,缓冲区是指在游戏界面外一圈区域,不设置缓冲区的话会有一些麻烦
- {
- for (int j = 0; j < col + 2; j++)
- {
- init[i][j] = 0;
- }
- }
-
- srand((int)time(0));
-
- int a = boom;//初始化雷的数量
- while (a > 0)//设置循环,初始化雷的位置,雷的位置是随机出现的
- {
- int row1 = rand() % row + 1; //缓冲区不可出现雷,rand%10是指[0,10),加一使得雷在界面内出现
- int col1 = rand() % col + 1;
-
- if (init[row1][col1] == 0)
- {
- init[row1][col1] = 6;//将雷所在数组元素设为6
- a--;
- }
- }
-
- for (int i = 1; i <= row; i++)
- {
- for (int j = 1; j <= col; j++)
- {
- if (init[i][j] == 0)
- {
- for (int m = i - 1; m <= i + 1; m++)//设置两个循环,获取某一位置周围雷的数量
- {
- for (int n = j - 1; n <= j + 1; n++)
- {
- if (init[m][n] == 6)
- {
- init[i][j]++;
- }
-
- }
- }
- }
- }
- }
-
- for (int i = 1; i <= row ; i++)//把数组的每个元素都+100,通过加载图片成为初始状态
- {
- for (int j = 1; j <= col ; j++)
- {
- init[i][j] = init[i][j] + 100;
- }
- }
- }
当二维数组元素值处于不同区间时,我们打印不同的图片,就可以实现每个格子不同的状态,注意一定要控制好值和范围的关系,否则可能会出现插了棋子却又可以左键点击出炸弹等尴尬的Bug,我所定义的范围肯定没有问题,可以放心用
- void PaintGame()
- {
- for (int i = 1; i <= row ; i++)
- {
- for (int j = 1; j <= col; j++)
- {
- if (init[i][j] >= 0 && init[i][j] <= 6)
- {
- putimage((i - 1) * size, (j - 1) * size, &img[init[i][j]]);
- }
- if (init[i][j] >= 100 && init[i][j] <= 106 || init[i][j] >= 300 && init[i][j] % 200 > 10)//初始时为100到106,大于300以后有插旗与取消状态,除以200取余大于10,则为插旗后取消旗子
- {
- putimage((i - 1) * size, (j - 1) * size, &img[8]);
- }
- if (init[i][j] >= 200 && init[i][j] <= 206 || init[i][j] >= 300 && init[i][j] % 200 < 10)//同上,小于10则为插旗
- {
- putimage((i - 1) * size, (j - 1) * size, &img[7]);
- }
- if (init[i][j] == -101)
- {
- putimage((i - 1) * size, (j - 1) * size, &img[0]);
- }
- }
- }
- }
玩扫雷时我们发现,当点击目标周围没有炸弹时,我们点击一下会点开一片,可以称之为游戏独特的机制,用Expand函数来实现
- void Expand(int m, int n)
- {
- if (m >= 1 && n >= 1 && m <= row && n <= col)//设置好,小心超出范围
- {
- for (int i = m - 1; i <= m + 1; i++)
- {
- for (int j = n - 1; j <= n + 1; j++)
- {
- if (init[i][j] % 100 == 0)
- {
- init[i][j] = -101; //换一个新的独特的值,避免套娃造成bug
- Expand(i, j); //逢0递归
- }
- if (init[i][j] % 100 >= 1 && init[i][j] % 100 <= 5)
- {
- init[i][j] = init[i][j] % 100;
- }
- else
- {
- init[i][j] = init[i][j];
- }
- }
- }
- }
- else
- {
- init[m][n] = init[m][n];
- }
- }
总体来看很好理解,通过鼠标的点击,来改变点击位置对应数组元素的值,点击方式的不同,即左键点击和右键点击,值的改变也不同,一定要设置好改变的值,否则会出现插了棋子却又可以左键点击等Bug
- void PlayGame()
- {
- MOUSEMSG msg = { 0 };
- msg = GetMouseMsg();
- int m, n;
- m = msg.x / size + 1; //加一使该函数的操作作用于init[1][1]及之后的元素,因为打印时外圈的全为0的行列不打印
- n = msg.y / size + 1;
- if (msg.uMsg == WM_LBUTTONDOWN)
- {
- PlaySound(TEXT("b.wav"), NULL, SND_FILENAME | SND_ASYNC);
- if ( init[m][n] >= 100 && init[m][n] <= 106 || init[m][n] >= 300 && init[m][n] % 200 > 10)//当前格子赋值为100到106(初始),或者300以上并且除以200余数小于10时,因为旗子状态不能变为数
- {
- init[m][n] = init[m][n] % 100;//取除以10的余数,即可得原值
-
- if (init[m][n] == 0)//当选中位置元素为0时,扩散
- {
- Expand(m, n);
- }
- }
- else
- {
- init[m][n] = init[m][n];
- }
- }
-
- if (msg.uMsg == WM_RBUTTONDOWN)
- {
- PlaySound(TEXT("b.wav"), NULL, SND_FILENAME | SND_ASYNC);
- if (init[m][n] > 6)//因为所有值都大于0,所以小于等于6时是12345和炸
- {
- init[m][n] = init[m][n] + 100;
- }
- else
- {
- init[m][n] = init[m][n];
- }
- }
- }
- void JudgeMent()
- {
- while (1)
- {
- PaintGame();
- PlayGame();
-
- int boomnum = 0;//初始化踩中炸弹数量
- int boomleft = boom;//初始化剩余炸弹数量
-
- for (int i = 1; i <= row; i++)
- {
- for (int j = 1; j <= col; j++)
- {
- if (init[i][j] == 6)
- {
- boomnum++;//踩中炸弹
- }
- if (init[i][j] == 206 || init[i][j] >= 300 && init[i][j] % 200 == 6)
- {
- boomleft--;
- }
- }
- }
- if (boomnum == 1)//踩中炸弹即为失败
- {
- PlaySound(TEXT("a.wav"), NULL, SND_FILENAME | SND_ASYNC);
- putimage(0, 0, &img[9]);
- break;
- }
- if (boomleft == 0)
- {
- PlaySound(TEXT("c.wav"), NULL, SND_FILENAME | SND_ASYNC);
- putimage(0, 0, &img[10]);
- break;
- }
- }
- }
- int main()
- {
- load();
- initgraph(row * size, col * size);
- InitGame();
- JudgeMent();
- getchar();
- return 0;
- }
以上即为扫雷小游戏的全部实现过程,难点在于选择的值范围对格子状态的影响以及递归函数的构造,总体难度不大。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。