基于EasyX的扫雷游戏
Posted jzdnkbd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于EasyX的扫雷游戏相关的知识,希望对你有一定的参考价值。
基于EasyX的扫雷游戏
一、预备知识
1.使用EasyX必须要知道的一些基础函数
2.选择结构 if , switch
3.循环结构 for, while
4.多维数组 arr1[N], arr2[N][N] , arr3[N][N][N]
5.函数封装
二、游戏逻辑
想要写出推箱子,首先要知道推箱子游戏都有哪些元素和规则
1.扫雷元素
主要可以分成三类
1.没有打开个格子
2.打开的格子
3.被标记的格子
有了素材,先来一个加载资源函数Loadimg()
#define SIZE 25//图片大小
IMAGE img[13];//存放图片数组
void Loadimg()
{
loadimage(&img[0] ,L"./images/0.jpg",SIZE,SIZE);
loadimage(&img[1] ,L"./images/1.jpg",SIZE,SIZE);
loadimage(&img[2] ,L"./images/2.jpg",SIZE,SIZE);
loadimage(&img[3] ,L"./images/3.jpg",SIZE,SIZE);
loadimage(&img[4] ,L"./images/4.jpg",SIZE,SIZE);
loadimage(&img[5] ,L"./images/5.jpg",SIZE,SIZE);
loadimage(&img[6] ,L"./images/6.jpg",SIZE,SIZE);
loadimage(&img[7] ,L"./images/7.jpg",SIZE,SIZE);
loadimage(&img[8] ,L"./images/8.jpg",SIZE,SIZE);
loadimage(&img[9] ,L"./images/9.jpg",SIZE,SIZE);
loadimage(&img[10],L"./images/10.jpg",SIZE,SIZE);
loadimage(&img[11],L"./images/11.jpg",SIZE,SIZE);
loadimage(&img[12],L"./images/12.jpg",SIZE,SIZE);
}
2.扫雷规则
1.左键点击未被打开的格子,可以打开格子
2.右键点击未被打开的格子,可以标记格子
3.被标记的格子不能被打开
3.被标记的格子再右键时,可以解除标记
4.如果打开后格子是空的,则自动打开周围的八个格子
5.自动打开的格子也遵循规则4
6.如果打开的格子里面是雷,则游戏失败
7.如果所有非雷格子均被打开,则游戏获胜
(格子的数字代表它周围九宫格内雷的数量)
三、游戏设计
知道游戏元素和规则就可以开始设计游戏了
1.地图设计
地图内的数字代表它周围九宫格内雷的数量,看一下图就应该可以理解了,这次采用地图随机生成(为了避免大家记雷的位置),需要用<time.h>里的生成随机数,先写一个初始化地图函数Initmap()
#define NUM 10//地图行列数
int map[NUM][NUM]={0};
void Initmap()
{
//----------随机设置雷----------
srand((unsigned)time(NULL));//根据时间设置随机数种子
for(int k=0;k<NUM; )
{
int x=rand()%NUM;//生成0 ~ 9的随机数
int y=rand()%NUM;//为避免产生相同的坐标,采用下面的方式
if(map[x][y]==0)
{//如果格子为空,则设置雷
map[x][y]=9;//雷是9
k++;
}
}
//如果是雷,则雷周围九宫格内数字均+1
for(int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
if(map[i][j]==9)
{//如果是雷
for(int a=i-1;a<=i+1;a++)
{//遍历该雷周围的九宫格
for(int b=j-1;b<=j+1;b++)
{
if(a>=0 && b>=0 && a<NUM && b<NUM && map[a][b]!=9)
{//判断数组是否越界
map[a][b]++;//不越界则+1
}
}
}
}
}
}
//盖上格子 所有数字 +10,(点击打开格子 数字-10)
for(int r=0;r<NUM;r++)
{
for(int c=0;c<NUM;c++)
{
map[r][c]+=10;
}
}
}
由上面的元素分类可以知道,游戏地图数据分为三类
- 被打开的格子 0 ~ 9
- 未被打开的格子 10 ~ 19
- 被标记的格子 20 ~ 29
也就是,对格子进行+10处理,+10代表另一种状态,现在可以根据状态绘制地图,写一个Drawmap()函数
void Drawmap()
{
for(int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
if(map[i][j]>=10 && map[i][j]<20)
{//如果图还没点开,且未被标记,贴格子
putimage(i*SIZE,j*SIZE,&img[10]);
}
else if(map[i][j]>=20)
{//如果被标记,贴标记
putimage(i*SIZE,j*SIZE,&img[11]);
}
else
{//剩下的按数值贴图
putimage(i*SIZE,j*SIZE,&img[ map[i][j] ]);
}
}
}
}
2.点击设计
上文提到
1.左键点击未被打开的格子,可以打开格子
2.右键点击未被打开的格子,可以标记格子
3.被标记的格子不能被打开
3.被标记的格子再右键时,可以解除标记
首先要找到鼠标位置,然后根据鼠标点击的情况,左键还是右键,分写不同的处理,所有内容写在Hitimg()函数内
ExMessage m;//消息全局变量
int ipos=-10,jpos=-10;//记录鼠标位置
int count=90;//总共非雷格子数
void Hitimg()
{
m = getmessage(EM_MOUSE);//得到鼠标消息
if(m.message == WM_LBUTTONDOWN)
{//如果鼠标左键按下
ipos=m.x/SIZE;//换算鼠标位置
jpos=m.y/SIZE;
if(map[ipos][jpos]>=10 && map[ipos][jpos]<20)
{//如果格子还没被点开 且未被标记
count--;//非雷格子数减少
map[ipos][jpos]-=10;//打开
}
}
if(m.message == WM_RBUTTONDOWN)
{//如果鼠标右键按下
ipos=m.x/SIZE;//换算鼠标位置
jpos=m.y/SIZE;
if(map[ipos][jpos]>=10 && map[ipos][jpos]<20)
{//如果格子还没被点开
map[ipos][jpos]+=10;//标记
}
else if(map[ipos][jpos]>=20)
{//如果格子被标记
map[ipos][jpos]-=10;//去掉标记
}
}
}
上文提到
4.如果打开后格子是空的,则自动打开周围的八个格子
5.自动打开的格子也遵循规则4
这个就比较有趣了,仔细想想,这不就是递归吗,因为每次格子位置都不一样,需要传个 格子位置 参数,写个Openmap(int ipos,int jpos)函数
void Openmap(int ipos,int jpos)
{//如果是空白则打开别打空白
if(map[ipos][jpos]==0)
{//如果是空格子
for(int a=ipos-1;a<=ipos+1;a++)
{ //遍历格子周围的九宫格
for(int b=jpos-1;b<=jpos+1;b++)
{
if(a>=0 && b>=0 && a<NUM && b<NUM)
{//判断数组是否越界
if(map[a][b]>=10 && map[a][b]<=18)
{//如果周围是没被打开的格子
map[a][b]-=10;//打开格子
count--;//非雷格子数减少
Openmap(a,b);//递归打开 被打开格子周围的格子
}
}
}
}
}
}
3.结束设计
上文提到
6.如果打开的格子里面是雷,则游戏失败
7.如果所有非雷格子均被打开,则游戏获胜
是不是很容易想到,
游戏失败条件就是map[ipos][jpos]==9
游戏获胜条件就是非雷格子数为灵count==0
如果游戏失败也把别的雷显示出来,并且点的雷是红的,写一个函数显示所有雷Showallmines()
void Showallmines()
{
for(int i=0;i<NUM;i++)
{
for(int j=0;j<NUM;j++)
{
if(map[i][j]==19 && map[i][j]!=9)
putimage(i*SIZE,j*SIZE,&img[12]);
if(map[i][j]==9)
putimage(i*SIZE,j*SIZE,&img[9]);
}
}
}
4.整体设计
下面把上面的函数组合起来就是推箱子游戏,再来点音乐
#include<stdio.h>
#include<time.h>
#include<easyx.h>//图形库
#include<mmsystem.h>//音乐
#pragma comment(lib,"winmm.lib")//库文件
int main()
{
initgraph(SIZE*10,SIZE*10);//创建窗口
Loadimg(); //加载图片资源
Initmap();//初始化地图
BeginBatchDraw();//批量绘图开始
Drawmap();//贴图
EndBatchDraw();//批量绘图结束
//循环播放背景音乐
mciSendString(L"open ./images/bg.mp3 ", 0, 0, 0);
mciSendString(_T("play ./images/bg.mp3 repeat"), 0, 0, 0);
while(true){
if(map[ipos][jpos]==9)
{//如果游戏失败
Showallmines();//显示所有雷
mciSendString(L"close ./images/bg.mp3 ", 0, 0, 0);//关闭背景音乐
PlaySound(L"./images/over.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放失败音乐
MessageBox(NULL,_T("游戏结束,你输了,-_-||"),_T("游戏提示"),MB_OK);
break;
}
else if(count==0)
{//如果游戏胜利
Drawmap();
mciSendString(L"close ./images/bg.mp3 ", 0, 0, 0);//关闭背景音乐
PlaySound(L"./images/success.wav", nullptr, SND_FILENAME | SND_ASYNC);//播放胜利音乐
MessageBox(NULL,_T("游戏结束,恭喜你,你赢了!"),_T("游戏提示"),MB_OK) ;
break;
}
Drawmap();//更新地图
Hitimg();//点击格子图片
Openmap(ipos,jpos);//递归打开空格子
}
system("pause");
return 0;
}
把上面所有代码复制到一个cpp文件里,再把素材改好命名放到images文件夹里,images文件夹在cpp文件旁边,就可以编译运行了!
图片音乐素材及可执行程序都在我的资源中,需要的可以进行下载
以上是关于基于EasyX的扫雷游戏的主要内容,如果未能解决你的问题,请参考以下文章