写在前头
这姑且也算是笔者第一篇博客,写来还是多少有点小激动的,一口气写了上万字,希望各位能积极点赞关注收藏留言与作者互动,让作者体验一下csdn社区的良好氛围
你是否还在为整日面对着无聊的黑色窗口感到厌倦?
你是否对游戏制作感兴趣却无从下手而感到苦恼?
亦或是不知道自己该学点什么?
我向你强烈推荐这款Easyx库,这款功能极其强大的库能满足你对动画(绝大部分)的想象,还能作为一个技能点常亮于你的技能树之上。
所以这篇文章就将带领大家完成一个基于easyx库的扫雷项目,在这篇文章中你可以学到包括但不限于:
1、库的下载与部分函数的使用 2、扫雷的基本逻辑与实现 3、基于easyx库的图片载入
4、文件打包
在这里不得不说的是,这篇文章会教一些图形化实现,如果你不想看扫雷的逻辑可以直接跳转至图像化实现。但这篇文章不会拘泥于对easyx库函数的解释,更多的是一个运用实例,如果你想了解更详细的easyx函数请移步至easyx库文档,此外作者认为学习函数并调用他们去完成一个项目远比单调的背函数学到的东西更多,这个项目的品尝方法有很多,比如直接用已有的逻辑自行实现图形化,或者把本应由鼠标点击输入方法改为键盘输入,亦或是看看已完工的项目的代码和自己有什么差别,其中作者对每段代码都进行了解读,可能过于冗长,所以作者最建议的是,直接去看项目的总代码,自行理解与实操,有不懂的地方再回去看作者解读,还有记得点赞关注评论收藏转发希望读者们自行选择适合自己的学习道路。
其中头文件主要为声明和少量解释,main文件是整个扫雷的实现流程,game文件是各种函数
该项目的完成离不开easyx库,在此表达对easyx库作者及各位大能的感谢,也希望各位多多了解easyx库,遇到各类问题也可以去easyx库官网查看解决方法easyx官网
PS:有任何问题或学术交流加Q:2908692481,来找作者玩。
图片文件和游戏本体都在这:作者真是大公无私啊,快快点赞 提取码:hjnb
最终效果预览
我们的最终结果大致是
有时间模块,也比较像传统的扫雷,作者认为这个扫雷放眼全网已经算完成度蛮高也蛮漂亮的了。
正文
还是碎碎念
在这个项目中笔者收获良多、其中最重要几点需要在讲解开始前告诉大家:
1、在完成项目的过程中,一定要有一个良好的思路,即明确整一个实现过程,比如先写完扫雷最核心的功能,再去研究鼠标的读入,再去研究图片的导入与输出。明确当前工作目标是保证工作速度的基础。
2、在完成项目的过程中,一定要多写批注,保证项目的可读性,至少你察觉某个模块可能出问题时,你得很多地找出这个模块。
前期工作(库的下载)
在这里浅谈easyx库的下载
1、打开easyx库官网,并点击红色的大大的下载按钮
2、下载完成后点开安装包,easyx库的安装包会自动识别安装路径,点击安装即可
3、然后你就可以打开你的vs创建项目,添加头文件#include<graphics.h>开始写代码啦。
扫雷逻辑实现
对该章节有任何问题请读者自行移步至扫雷网页版查看。
也欢迎来找作者讨论,加Q:2908692481
局前操作
格子生成
首先我们要明白扫雷中一个格子有多少个属性,作者认为有4个,分别是:
1、他有没有被点开 2、他是不是炸弹 3、他有没有被插旗子 4、他周围有多少个炸弹
然后就可以创建一个类,即对应着每一个格子
struct ele {
int data;
bool know, bomb, flag;
};
extern ele el[12][12];
因为这段代码是写在头文件的所以在声明el数组前要加上extern,等到时候作者有时间会写一篇关于头文件使用的心得,如果嫌麻烦可以直接全部代码写在一个源文件里面,这样就可以不用加extern。(12*12的格子是为了防止越界) 。
//刷新数值
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
el[i][j].data = 0;
el[i][j].bomb = 0;
el[i][j].flag = 0;
el[i][j].know = 0;
}
}
每次游戏开始即没生成炸弹前,每个格子都不是炸弹、没被插旗子、没被点开、数字也为0(即周围有0个炸弹)。
地雷生成
然后可以开始生成地雷,作者选用了c++自带的rand()语句(贪图方便)
随机一个x,再随机一个y,如果这个格子不是地雷(即bomb==0)使得他变成炸弹,四周围格子中数字++,如果是炸弹就不进行以上操作。
//创造炸弹
srand(time(0));
int x, y;
for (int i = 0; i < 10; i++) {
x = 1 + rand() % 9;
y = 1 + rand() % 9;
if (el[x][y].bomb) {
i--;
continue;
}
int j, k;
for (j = -1; j <= 1; j++) {
for (k = -1; k <= 1; k++) {
if (j == 0 && k == 0)el[x + j][y + k].bomb = 1;
else el[x + j][y + k].data++;
}
};
}
其中srand()是放入随机种子,有srand()才能用rand()生成随机数,我把随机种子定为了time(0),即1970年1月1日00:00:00至当前的秒数,他是持续变化的,所以不用担心生成重复的结果。
游戏结束判定
怎么样才算游戏结束呢,很简单,就是把格子全都开完了,一个9*9棋盘有81个格子,有10个炸弹,也就是要打开71给格子才算胜利
extern int allspace;
allspace = 0;
设置当前已开格子为0个,循环格子数小于71,持续接收开格子的信号
while (allspace < 71) {
游戏内容
}
局前操作合并
如果你看到这里,那么恭喜你,你已经完成了所有的开局操作,我们可以把上述操作合并一下:
void refresh() {
//刷新数值
for (int i = 0; i < 12; i++) {
for (int j = 0; j < 12; j++) {
el[i][j].data = 0;
el[i][j].bomb = 0;
el[i][j].flag = 0;
el[i][j].know = 0;
}
}
//刷新空格子数
allspace = 0;
//创造炸弹
srand(time(0));
int x, y;
for (int i = 0; i < 10; i++) {
x = 1 + rand() % 9;
y = 1 + rand() % 9;
if (el[x][y].bomb) {
i--;
continue;
}
int j, k;
for (j = -1; j <= 1; j++) {
for (k = -1; k <= 1; k++) {
if (j == 0 && k == 0)el[x + j][y + k].bomb = 1;
else el[x + j][y + k].data++;
}
}
}
}
局中操作
扫雷的操作并不复杂,无非就是开格子,插旗子,其中又分为了以下几种。
1、如果一个格子没被开过也没插旗子:
左键他就会开启他,如果他是炸弹游戏结束,不是炸弹就开启这个格子,如果他是数字0那就自动开四周的格子(因为他周围一定没有炸弹所有帮你开好了)如果他不是数字0就停止继续开四周的格子。
右键他就会为他插上旗子。
2、如果一个格子没被开过插了旗子:
左键他没有反应(旗子的作用就是防止误触与标识)。
右键他就会取消他的旗子。
3、如果一个格子被开过了:
左键他没有反应。
右键他的话(这是一个扫雷的小技巧吧,不实现也不影响扫雷的游玩)如果他在周围的旗子数和他显示的数字一样,那么就相当于你告诉系统,你已经猜好雷的位置了,就会开启周围九个中所有没插旗的格子,如果其中有炸弹那么直接游戏结束。
综上,