/*==========================================================================================
文件名:main.cpp
项目名称:扫雷游戏
实现效果:1.有一个游戏初始界面,可以供玩家,选择难度,星级
2.游戏会显示雷的剩余数,时间的流动,还要金手指的使用
作者心得以及给观看学习者一些观看思路:
次游戏主要部分是通过数组的值进行图片的切换
程序的执行路线是: index->initgame
|
paly <-->drawMap
| |
jingshozhi swap cloc
游戏失败会回调index
学习观看代码者可以根据这个路线来
《华少》
===========================================================================================*/
/*===================================包含头文件============================================*/
#include<graphics.h> //次头文件不是标准库自带,需要自己下载导入,这个程序主要的用到的
#include<stdio.h>
#include<stdlib.h> //随机数 rand() 包含头
#include<time.h> //需要time协助rand()
/*=====================================枚举声明=============================================*/
enum Ctype{ qiang = 10, lei = 9,biankuan=-3,s=10};//qiang 表示右边的墙 9 表示雷 边框 表示边框
/*====================================全局变量==============================================*/
int weith = 0, height = 0; //地图大小
int mapSize = 0; //游戏区域大小
int leisum = 0; //雷的数量
#define IMG 25 //图片显示大小
#define MAP 50 //存放游戏的数组大小
HWND hWnd; //窗口句柄
int win; //记录点开数
int feishu = 0; //分数
int shozhi = 0; //金手指数量
short sho = 0; //控制金手指数量
DWORD pretime, nowtime; //游戏时间
int sd, mu, hw; //完成时分秒的效果
/*====================================函数声明==============================================*/
void drawMap(int map[MAP][MAP], IMAGE *img); //用于游戏画面刷新
int play(int map[MAP][MAP], IMAGE *img); //用于游戏鼠标消息控制
void swap(int map[MAP][MAP], int x, int y); //用于玩家点击到周围没有雷的地方进行递归
void index(); //游戏菜单界面
void lookAllLei(int map[MAP][MAP]); //用于玩家失败后显示所有的雷
void cloc(); //用于时间控制
void jingshozhi(int map[MAP][MAP],int x,int y); //用于控制金手指
/*====================================游戏初始化============================================*/
void initgame(int Size, int sum){
int map[MAP][MAP] = { 0 }; //初始化数组数据
mapSize = Size; //用index传来的Size初始化扫雷面积
weith = mapSize * IMG + 100; //窗口宽度,雷区面积*图片大小 加上100是为了留地方显示数据
height = mapSize * IMG; //窗口高度
pretime = GetTickCount(); //控制时间显示,在这记录一个时间
feishu = 0; //分数,分数关系到金手指数量
shozhi = 0; //金手指可使用数量
sho = 1; //关系到金手指数量计算
sd = 0, mu = 0, hw = 0; //用于时间计算
leisum = mapSize*mapSize / sum; //雷的数量
int count = leisum; //记录开始总雷数 关系到游戏赢的控制
win = 0; //记录已经点开数 关系到游戏赢的控制
for (int i = 0; i < mapSize; i++) //初始化雷区
{
for (int j = 0; j < mapSize; j++)
{
map[i][j] = qiang;
}
}
srand((unsigned)time(NULL)); //随机数初始化
int m, n; //用于记录随机产生的值
for (int i = 0; i < leisum;) //放雷
{
m = rand() % mapSize; //随机产生 0 到 mapSize的数 不包含mapSize
n = rand() % mapSize;
if (map[m][n] != -1) //如果此地方还不是雷
{
map[m][n] = -1; //给它赋值一个雷 -1代表雷
i++; //已经放好的雷加1
}
}
for (int x = 0; x < mapSize; x++) //生成周围雷数
{
for (int y = 0; y < mapSize; y++) //遍历雷区
{
if (map[x][y] == -1) //跳过雷
continue;
for (int i = x - 1; i <= x + 1; i++) //遍历周围
{
for (int j = y - 1; j <= y + 1; j++) //遍历周围
{
if (i >= 0 && i < mapSize&&j >= 0 && j < mapSize)//控制范围,防止越界,分别是上、下、左、右墙
{
if (map[i][j] == -1) //如果周围有一个雷
{
map[x][y]++; //这个点的值就加1
}
}
}
}
}
}
for (int i = 0; i < mapSize; i++) //初始化右边框位置
{
map[i][mapSize] = biankuan;
}
initgraph(weith, height); //初始化窗口
IMAGE img[22]; //图片数组
loadimage(&img[0], L"res/墙.jpg", IMG, IMG); //加载图片,存入图片数组,参数分别是 存入内存地址,图片位置,图片宽度,高度
loadimage(&img[1], L"res/雷.jpg", IMG, IMG);
loadimage(&img[2], L"res/边框.jpg",IMG, IMG);
loadimage(&img[3], L"res/0.jpg", IMG, IMG);
loadimage(&img[4], L"res/1.jpg", IMG, IMG);
loadimage(&img[5], L"res/2.jpg", IMG, IMG);
loadimage(&img[6], L"res/3.jpg", IMG, IMG);
loadimage(&img[7], L"res/4.jpg", IMG, IMG);
loadimage(&img[8], L"res/5.jpg", IMG, IMG);
loadimage(&img[9], L"res/6.jpg", IMG, IMG);
loadimage(&img[10], L"res/7.jpg", IMG, IMG);
loadimage(&img[11], L"res/8.jpg", IMG, IMG);
loadimage(&img[12], L"res/9.jpg", IMG, IMG);
loadimage(&img[13], L"res/标记.jpg", IMG, IMG);
loadimage(&img[14], L"res/不清楚.jpg", IMG, IMG);
hWnd = GetHWnd(); //窗口置前
while (1){
drawMap(map, img); //刷新界面
if (play(map,img) == 9) //如果play返回9 表示点到雷
{
lookAllLei(map); //显示所有类
drawMap(map, img); //刷新一下界面
MessageBox(hWnd, L"哎哟!", L"点到雷咯!",MB_OK);//弹出窗口
break; //跳出循环
}
if (win == mapSize*mapSize - count) //如果点开的数量等于雷区数量-总雷数
{
MessageBox(hWnd, L"666!", L"win!",MB_OK); //弹出窗口
drawMap(map, img); //刷新界面
break; //跳出循环
}
}
index(); //显示主界面
}
/*====================================刷新界面==============================================*/
void drawMap(int map[MAP][MAP],IMAGE *img){
for (int i = 0; i < mapSize+1; i++) //遍历数组
{
for (int j = 0; j < mapSize+1; j++)
{
switch (map[i][j]) //根据数组里的值显示不同的图片
{
case -1:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:
case qiang: putimage(j*IMG, i*IMG, &img[0]); break; //以上值显示方块 用于初始状态隐藏雷 和 周围雷数 通过点击消息 把 隐藏的雷什么的通过+值得到对应的值
case lei: putimage(j*IMG, i*IMG, &img[1]); break; //显示类
case biankuan: putimage(j*IMG, i*IMG, &img[2]); break; //右边框
case 20: putimage(j*IMG, i*IMG, &img[3]); break; //周围雷数0
case 21: putimage(j*IMG, i*IMG, &img[4]); break; //周围雷数1
case 22: putimage(j*IMG, i*IMG, &img[5]); break; //周围雷数2
case 23: putimage(j*IMG, i*IMG, &img[6]); break; //周围雷数3
case 24: putimage(j*IMG, i*IMG, &img[7]); break; //周围雷数4
case 25: putimage(j*IMG, i*IMG, &img[8]); break; //周围雷数5
case 26: putimage(j*IMG, i*IMG, &img[9]); break; //周围雷数6
case 27: putimage(j*IMG, i*IMG, &img[10]); break; //周围雷数7
case 28: putimage(j*IMG, i*IMG, &img[11]); break; //周围雷数8
case 29: putimage(j*IMG, i*IMG, &img[12]); break; //周围雷数9
case 39:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 58:case 59://标记
putimage(j*IMG, i*IMG, &img[13]); break;
case 49:case 60: case 61: case 62: case 63: case 64: case 65: case 66: case 67: case 68: case 69://问号
putimage(j*IMG, i*IMG, &img[14]); break;
}
}
}
if (feishu / (sho * 50) >= 1) //加金手指数量,用分数和sho变量控制
{
shozhi++;
sho += 2;
}
/*================================以下用于窗口显示文字===========================*/
TCHAR s[5];
_stprintf_s(s, _T("%-2d"), leisum); // 高版本 VC 推荐使用