C++桌面程序 扫雷教学

要学很简单 C/C++都能学 没有类

单纯想玩可以直接到最后下载放到桌面

目录 

 C++桌面程序 扫雷教学

创建项目

开始正式编辑

定义全局常量 和 变量

地图初始化 

初始化雷 (雷 -1)

提示周围的有几个雷

绘图

资源加载 (位图)

在窗口上绘制图

定时器消息

绘制地图

鼠标点击事件

鼠标左键按下

右键双击标记雷

右键按下 

右键松开

成品演示代码下载

 成品游玩视频


 C++桌面程序 扫雷教学

创建项目

0b24206fa25341989703db32ce221444.png

 选择 windows 桌面向导 点击下一步(有桌面程序自带的主代码)

b4997ff9863048fa9b9deb75be0e7506.png

 命名 选择 文件位置 点击创建

3c5a6fdc1f8f4095b50665c37b219cc7.png

 创建好后会有主代码(如果没有或想要自己创建 或者 想要了解是什么)

自建 以及每段的解释(VS给你创建的和这个会有些许出入但基本是这样)

#include<windows.h>

//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam);


//入口函数
int WINAPI WinMain(_In_ HINSTANCE hIns, _In_opt_ HINSTANCE hpreIns, _In_ LPSTR IpCmdLine, _In_ int nCmdShow)
{
	//窗口名(后面要一样防止出错提前定义)wchar_tz 字符串类型
	wchar_t wdLpszClassName[] = L"窗口名";

//注册窗口类
	//创建窗口类
	WNDCLASS wc;
	//申请缓冲区(两种不同的缓冲区)
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	//窗口背景色
	wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
	//光标(NULL 默认光标)
	wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
	//图标(NULL 默认图标)
	wc.hIcon = NULL; //LoadIcon(NULL, IDI_APPLICATION);
	//给当前程序实例句柄(HINSTANCE 实例句柄类)
	wc.hInstance = hIns;
	//给窗口处理函数
	wc.lpfnWndProc = WindowProc;
	//窗口类名称
	wc.lpszClassName = wdLpszClassName;
	//窗口菜单(NULL 不要菜单)
	wc.lpszMenuName = NULL;
	//窗口风格 (窗口( 水平有变化  或 垂直有变化)时 重绘)
	wc.style = CS_HREDRAW | CS_VREDRAW;
	//将以上赋值全部写入操作系统
	RegisterClass(&wc);

	//在内存创建窗口(返回值窗口句柄)HWND 窗口句柄
	HWND hwnd = CreateWindow(
		wdLpszClassName,      // 窗口名(要和 窗口类名称 相同)
		L"标题栏信息",          // 标题栏信息
		WS_OVERLAPPEDWINDOW,  // 窗口风格
		CW_USEDEFAULT,        // 位置 宽(可以用 整形 距离屏幕有多远的位置)
		CW_USEDEFAULT,        // 位置 高
		CW_USEDEFAULT,        // 大小 宽
		CW_USEDEFAULT,        // 大小 高
		NULL,                 // 父窗口(NULL 没有父窗口)
		NULL,                 // 菜单(NULL 没有)
		hIns,                 // 当前程序实例句柄
		NULL                  // 没什么用给 空就行了
	);

	//显示窗口(SW_SHOW 原样显示)
	ShowWindow(hwnd, SW_SHOW);

	//刷新窗口 不调也行(微软建议我们调)
	UpdateWindow(hwnd);

	//消息循环
	//MSG 是一个 结构体(用来保存 GetMessageW 捕住消息 的 )
	MSG msg;
	while (GetMessageW(&msg, NULL, 0, 0)) 
	{
		//翻译消息
		TranslateMessage(&msg);
		//派发消息(将消息 交给 窗口处理函数 来处理)
		DispatchMessage(&msg);
	}

	return 0;
}

//窗口处理函数(自定义,处理消息)
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msgID, WPARAM wParam, LPARAM lParam)
{
	switch(msgID)
	{
	case WM_DESTROY:
		//退出程序(给消息循环返回 0 退出循环)
		PostQuitMessage(0);
		break;
	}

	return DefWindowProc(hWnd, msgID, wParam, lParam);
}

开始正式编辑

定义全局常量 和 变量

我们先不管什么桌面不桌面的 把他当成你学过的那种去做一个C++的扫雷逻辑

定义全局的常量 (这里给一下萌新 解释一下 全局常量 是指 整个代码块不能修改的数值)

我这里是成品 一开始 可以把 行 列 雷 设置成10 这样方便调试(找错)其他4个可以先不管

#define COL 20  //行 (高)
#define ROW 40  //列 (宽)
#define MINE 100 //雷

#define BMPX 20 //位图X
#define BMPY 20 //位图Y

#define SCREENX 120 // 距离窗口X
#define SCREENY 50 // 距离窗口Y

让后是全局变量 (同理 这是全局可一改变的量)

这里为什么加2 知道的人肯定已经想到了(不知道的看到后面就懂了)

map_x 和 map_y 是绘制的位置 加二是让其有空隙看到不会太挤

Mine 雷个数让其可以改变

MineNum 标记雷的个数

//地图大小
int Map[ROW + 2][COL + 2];

//遮罩层
int MapCover[ROW + 2][COL + 2];

//标记雷
int MapMine[ROW + 2][COL + 2];

int map_x = BMPX + 2;
int map_y = BMPY + 2;


int Mine = MINE;
int MineNum;

地图初始化 

把上面三个二为数组初始化

for (int i = 0; i < ROW + 2; i++)
    {
        for (int j = 0; j < COL + 2; j++)
        {
            Map[i][j] = 0;
            MapCover[i][j] = 0;
            MapMine[i][j] = 0;
        }
    }

初始化雷 (雷 -1)

雷的位置不是固定的所以这里我们用随机数(可能有的人已经发现了 这里我们是伪随机)

把伪随机改为随机 只需要加一个时间值(   srand((unsigned int)time(NULL)); )

这里是还加了一条判断 应为 随机值有概率随机到一样的 导致雷刷到同一个位置

//雷
    for (int i = 0; i < MINE;)
    {
        int x_Mine = (rand() % ROW);
        int y_Mine = (rand() % COL);
        if (Map[x_Mine][y_Mine] != -1)
        {
            Map[x_Mine][y_Mine] = -1;
            i++;
        }

    }

提示周围的有几个雷

先找到每一个雷的位置在这定义一个函数去处理

雷的周围 应该是 

/*

(x+1 ,y - 1) (x+1 ,y)(x+1 ,y + 1)
(x ,  y-1)              ( 0)          (  x , y+1)
(x-1 ,  y+1)      (x-1 , y)       (x-1, y+1)
*/

看懂了这个因该就懂了

这里我们用一个循环去得到这九个位置(之前一个一个写麻烦还容易出错 哎~)

然后判断一下这九个位置只要不是雷就让它++ 这样我们就得到了雷周围的提示数据

容器上下多出2个共4个这里就体现出来了 如果雷在边上在判段的会就会保存 我们让他上下多两个就不会到边上了当仍方法有很多 也可以加些判段条件等等

void  get_board1_count(int Map[ROW + 2][COL + 2], int x, int y);

 //雷周围的
    for (int i = 0; i < ROW + 2; i++)
    {
        for (int j = 0; j < COL + 2; j++)
        {
            if (Map[i][j] == -1)
            {
                get_board1_count(Map, i, j);
            }


        }
    }

void  get_board1_count(int Map[ROW + 2][COL + 2], int x, int y)
{

    for (int i = x - 1; i <= x + 1; i++)
    {
        for (int j = y - 1; j <= y + 1; j++)
        {
            if (Map[i][j] != -1)
            {
                Map[i][j]++;
            }
            
        }
    }
}

绘图

资源加载 (位图)

位图头文件 一般是 #include "Resource.h" 如果不是 看一下有没有多建资源文件

位图就是图片 视图>其他窗口>资源视图

80c1614b25a649f1942e1da644b8c026.png

 点击添加资源

51c23407daad4e9db63227e4b0bd690e.png

 选择 Bitmap 文件 新建之后要自己编辑

如果有BMP图片文件就可以 导入(注意:一定是 BMP 的图片 导入后最好不要在动图片不然容易出错)

f61686d4d20246b6ab54182020afb3ff.png

 添加好后就可以看到 Bitmap 下的 就是你添加的图片

LoadBitmap(hInst, (wchar_t*)图片的ID);   //加载图片资源(要添加图片)

ff438098997f494b83eed45c3de48ce7.png

在窗口上绘制图

现在开始接触窗口编程了 不会很难

如果有觉得难的(开始接触如果决的有些难得人一定义撑过去  万事开头难 我是在B站自学 开始的装软件  搞配置 找教学 真的难 但是搞好之后慢慢的就好起来了 如果有不懂 的可以评论告诉我我尽力帮你解答)

有了基础信息之后我们来绘制看看

消息函数都是在 switch 里调用

初始化消息

SetTimer(hWnd, 1, 1000, NULL);  //创建一个定时器 让其每一秒开始检测一下有没有赢(感觉不应该放在这里 但也不清楚放哪感觉放哪都行 有清楚的可以评论一下)

//初始化
case WM_CREATE:
        SetTimer(hWnd, 1, 1000, NULL);
        CreateMap();
        break;

定时器消息

消息处理(定时器消息都会到这里处理)

//定时器
    case WM_TIMER:
    {
        TimeMine(hInst, hWnd);
    }
        break;

 每秒检测是否胜利 可以把其他的看完再来看这个

Mine 雷都排完了 并且 排的雷个数和雷相同

KillTimer(hWnd, 1);  // 结束定时器 (1 要结束的定时器 ID)

 MessageBox(hWnd, L"失败", L"结束", MB_OK); //提示框 (第一个文本是 内容 第二个是标题)

 Game(hInst, hWnd); //全部初始初始化

/检测是否胜利
void TimeMine(HINSTANCE hInst, HWND hWnd)
{
    if (Mine == 0 && MineNum == MINE)
    {
        KillTimer(hWnd, 1);
        MessageBox(hWnd, L"胜利", L"结束", MB_OK);  
        Game(hInst, hWnd);
    }

}

游戏逻辑 (初始化)

InvalidateRect(hWnd, NULL, true);  //地图重绘 (true 要删除 false 不删除)重绘

//游戏逻辑
void Game(HINSTANCE hInst, HWND hWnd)
{
    InvalidateRect(hWnd, NULL, true);

    Mine = MINE;
    MineNum = 0;
    CreateMap();

    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hWnd, &ps);

    DrawMap(hInst, hdc);

    EndPaint(hWnd, &ps);
}

WM_PAINT 这个是绘图消息要绘制的东西可以放到这里调用

(句柄你们暂时可以看作一个类型)

自定义定义一个函数 (把绘制代码放到函数里)

 DrawMap(hInst, hdc);  

case WM_PAINT:
    {
        //HDC 初始化 (HDC 是绘图句柄 要绘图就要用到)
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);
        
        // 绘画的内容(自定义的要绘画就写在这里)
        DrawMap(hInst, hdc);

         //绘画完释放
        EndPaint(hWnd, &ps);
    }

这里定义了两个函数一个绘制地图 一个绘制遮罩层

void DrawMap(HINSTANCE hInst, HDC hdc)
{
    
    printMap(hInst, hdc, BMPX, BMPY, SCREENX, SCREENY);
    //printMap(hInst, hdc, 20, 20, 250,0);

    OnLdownMap(hInst, hdc, BMPX, BMPY, SCREENX, SCREENY);
}

绘制地图

这里肯定有不少萌新需要头痛了这都是些什么呀

下面我给你们简单的讲解一下 (如果有需要 评论一下 我可以单独讲解一张)

函数参数

HINSTANCE hInst   //当前程序实例句柄

HDC hdc  //绘图句柄

x  y  //位图的小 (这是增加代码的复用性)

x1 y1 //距离窗口的位置 绘制位置

void printMap(HINSTANCE hInst, HDC hdc, int x, int y, int x1, int y1)
{
    HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP2);
    HDC hdcMap = CreateCompatibleDC(hdc);
    HGDIOBJ hPenDC = SelectObject(hdcMap, hBmp);

    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            if (Map[i][j] == -1)
            {
                TextOut(hdc, x1 + (i * map_x), y1 + (j * map_y), L"雷", 1);
            }
            else
            {
                BitBlt(hdc, x1 + (i * map_x), y1 + (j * map_y), x, y, hdcMap, x * Map[i][j] + Map[i][j], 0, SRCCOPY);
            }

        }
    }

HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP2);   //加载图片资源(要添加图片)IDB_BITMAP2 (图片的ID)
HDC hdcMap = CreateCompatibleDC(hdc);   // 构建一个虚拟区域  放到一个绘图句柄中
HGDIOBJ hPenDC = SelectObject(hdcMap, hBmp);   // 把位图 给 虚拟区域 让他在虚拟区域绘制 (返回原先的 绘图对象)

//中间是自由绘图 (可以根据实际情况自行调整)

TextOut    //文本绘制 (绘制文字)

(hdc,    //绘图句柄

x1 + (i * map_x),  // 距离窗口X 坐标 (X 左右)

y1 + (j * map_y), // 距离窗口Y 坐标(Y 上下)

L"雷",   // 要打印的文本

1   //文本的大小

);

BitBlt   // 图片打印

(

hdc,  // 窗口句柄

x1 + (i * map_x),   y1 + (j * map_y),  // 距离窗口X  Y 坐标

x,  y,    //图片的大小 X Y

hdcMap,  //你创建的虚拟区域绘图句柄

x * Map[i][j] + Map[i][j],  0,   // 从虚拟区域 的 什么位置开始绘制(就是图片的什么位置)

SRCCOPY   //成像方法 (这里这个是原样成像)

);

SelectObject(hdcMap, hPenDC); //用返回的原先对象把虚拟区域的位图拿走
DeleteObject(hBmp);    //位图释放
DeleteDC(hdcMap);   //虚拟区域释放

雷没有绘图的原因没有美术的天赋好难 还是做两个框框容易

鼠标点击事件

鼠标事件讲解

附带信息:
wParam  其他按键的状态(Ctrl Shift …)
lParam  鼠标的位置、窗口客户区坐标系
LOWORD(lParam)  X 坐标位置 返回值(short)
HIWORD(lParam)  Y 坐标位置

双击消息://使用时需要在注册窗口类的时候添加 CS_DBLCLKS 风格(在注册窗口类里找到  wcex.style 后面加上 CS_DBLCLKS ( | 添加不同效果 有点类似于 || 或者))

        //鼠标左键按下
    case WM_LBUTTONDOWN:
        OnLdown(hInst, lParam, hWnd, g_hOutput);
        break;
        //鼠标右键双击
    case WM_RBUTTONDBLCLK:
        TabMine(hInst, lParam, hWnd, g_hOutput);
        break;
        //鼠标右键按下
    case WM_RBUTTONDOWN:
        OnRdown(hInst, lParam, hWnd, g_hOutput);
        break;
        //鼠标右键松开
    case WM_RBUTTONUP:
        OnRup(hInst, lParam, hWnd, g_hOutput);
        break;

鼠标左键按下

左键按下我们然他 按下位置显示处理 是零的话就让他延申

//也是初始化(绘图消息外绘图用)

 HDC hdc = GetDC(hWnd); 

ReleaseDC(hWnd, hdc);

void OnLdown(HINSTANCE hInst, LPARAM lParam, HWND hWnd, HANDLE g_hOutput)
{
    HDC hdc = GetDC(hWnd);
    //TCHAR szText[256];

    HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP2);
    HDC hdcMap = CreateCompatibleDC(hdc);
    HGDIOBJ hPenDC = SelectObject(hdcMap, hBmp);

    for (int i = 0; i < ROW + 2; i++)
    {

        for (int j = 0; j < COL + 2; j++)
        {
            if (LOWORD(lParam) >= SCREENX + (i * map_x) && LOWORD(lParam) <= (SCREENX + (i * map_x)) + BMPX
                && HIWORD(lParam) >= SCREENY + (j * map_y) && HIWORD(lParam) <= (SCREENY + (j * map_y)) + BMPY && MapCover[i][j] == 0)
            {
                if (Map[i][j] == -1)
                {
                    KillTimer(hWnd, 1);
                    printMap(hInst, hdc, BMPX, BMPY, SCREENX, SCREENY);
                    MessageBox(hWnd, L"失败", L"结束", MB_OK);

                    Game(hInst, hWnd);

                    /*CreateMap();
                    DrawMap(hInst, hdc);*/

                }
                else if (Map[i][j] >= 0)
                {
                    MapCover[i][j] = 1;
                    MapCoverDown(hdc, hdcMap, i, j, SCREENX, SCREENY);
                }
            }
        }
    }


    SelectObject(hdcMap, hPenDC);
    DeleteObject(hBmp);
    DeleteDC(hdcMap);

    ReleaseDC(hWnd, hdc);

}

if 判断的是图片位置区间 并且 是没有打开的图不能

 if (Map[i][j] == -1)  // 点击的位置是雷的话我们要做的

KillTimer(hWnd, 1);  // 结束定时器

printMap(hInst, hdc, BMPX, BMPY, SCREENX, SCREENY); //之前写的 绘图 函数

 MessageBox(hWnd, L"失败", L"结束", MB_OK); //提示框

else if (Map[i][j] >= 0) // 点击的位置不是雷的话我们要做的

 MapCover[i][j] = 1;  // 让遮罩层赋值1(之后1 就是打开)

MapCoverDown(hdc, hdcMap, i, j, SCREENX, SCREENY);  //递归函数(自定义)

注意: 一定要设置不能超过行高(我这里就忘了导致搞了1个多小时 才发现我们有4行初始化是隐藏掉的)

void MapCoverDown(HDC hdc, HDC hdcMap, int x, int y, int x1, int y1)
{
    BitBlt(hdc, x1 + (x * map_x), y1 + (y * map_y), BMPX, BMPY, hdcMap, BMPX * Map[x][y] + Map[x][y], 0, SRCCOPY);

    if (Map[x][y] == 0)
    {
        for (int i = x - 1; i <= x + 1; i++)
        {
            for (int j = y - 1; j <= y + 1; j++)
            {
                //只有上下左右(有可能只有斜角是零)
                if ((i == x && j != y) || (j == y && i != x))
                {
                    把遮罩层打开(应为递归的时候是 再次进入是根据地图大小来的 所以要限制一下递归的 x y)
                    if ((i >= 0 && i < ROW && j >= 0 && j < COL) && MapCover[i][j] == 0)
                    {
                        MapCover[i][j] = 1;
                        BitBlt(hdc, x1 + (i * map_x), y1 + (j * map_y), BMPX, BMPY, hdcMap, BMPX * Map[i][j] + Map[i][j], 0, SRCCOPY);

                        MapCoverDown(hdc, hdcMap, i, j, x1, y1);
                    }
                } 
                
            }
        }
    } 
        
}  

右键双击标记雷

标记雷的位置

没有标记的话 就标记  MapMine[i][j] = 1; 标记的个数+1   MineNum++;

标记的话 就取消标记 MapMine[i][j] = 0; 标记的个数-1   MineNum--;

void TabMine(HINSTANCE hInst, LPARAM lParam, HWND hWnd, HANDLE g_hOutput)
{

    HDC hdc = GetDC(hWnd);

    HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP3);
    HDC hdcCover = CreateCompatibleDC(hdc);
    HGDIOBJ hPenDC = SelectObject(hdcCover, hBmp);

    for (int i = 0; i < ROW + 2; i++)
    {

        for (int j = 0; j < COL + 2; j++)
        {
            if (LOWORD(lParam) >= SCREENX + (i * map_x) && LOWORD(lParam) <= (SCREENX + (i * map_x)) + BMPX
                && HIWORD(lParam) >= SCREENY + (j * map_y) && HIWORD(lParam) <= (SCREENY + (j * map_y)) + BMPY && MapCover[i][j] == 0)
            {
                if (MapMine[i][j] != 1)
                {
                    MineNum++;
                    MapMine[i][j] = 1;
                    
                    BitBlt(hdc, SCREENX + (i * map_x), SCREENY + (j * map_y), BMPX, BMPY, hdcCover, 21, 0, SRCCOPY);
                    if (Map[i][j] == -1)
                    {
                        Mine--;
                    }
                }
                else if (MapMine[i][j] == 1)
                {
                    MineNum--;
                    MapMine[i][j] = 0;
                    BitBlt(hdc, SCREENX + (i * map_x), SCREENY + (j * map_y), BMPX, BMPY, hdcCover, 0, 0, SRCCOPY);
                    if (Map[i][j] == -1)
                    {
                        Mine++;
                    }
                }
            }
        }
    }


    SelectObject(hdcCover, hPenDC);
    DeleteObject(hBmp);
    DeleteDC(hdcCover);

    ReleaseDC(hWnd, hdc);
}

右键按下 

让他打印周围提示框

//右键按下
void OnRdown(HINSTANCE hInst, LPARAM lParam, HWND hWnd, HANDLE g_hOutput)
{
    HDC hdc = GetDC(hWnd);

    HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP3);
    HDC hdcCover = CreateCompatibleDC(hdc);
    HGDIOBJ hPenDC = SelectObject(hdcCover, hBmp);

    for (int i = 0; i < ROW + 2; i++)
    {

        for (int j = 0; j < COL + 2; j++)
        {
            if (LOWORD(lParam) >= SCREENX + (i * map_x) && LOWORD(lParam) <= (SCREENX + (i * map_x)) + BMPX
                && HIWORD(lParam) >= SCREENY + (j * map_y) && HIWORD(lParam) <= (SCREENY + (j * map_y)) + BMPY
                && MapCover[i][j] == 1 && Map[i][j] != 0)
            {
                pointMine(hInst,hdc, hdcCover, i, j);
            }
        }
    }


    SelectObject(hdcCover, hPenDC);
    DeleteObject(hBmp);
    DeleteDC(hdcCover);

    ReleaseDC(hWnd, hdc);
}

void pointMine(HINSTANCE hInst, HDC hdc, HDC hdcCover, int x, int y)
{
    for (int i = x - 1; i <= x + 1; i++)
    {
        for (int j = y - 1; j <= y + 1; j++)
        {
            if ((i >= 0 && i < ROW && j >= 0 && j < COL) && MapCover[i][j] == 0 && MapMine[i][j] != 1)
            {
                BitBlt(hdc, SCREENX + (i * map_x), SCREENY + (j * map_y), BMPX, BMPY, hdcCover, 42, 0, SRCCOPY);

            }

        }
    }
}

右键松开

周围变回去

//右键松开
void OnRup(HINSTANCE hInst, LPARAM lParam, HWND hWnd, HANDLE g_hOutput)
{
    HDC hdc = GetDC(hWnd);

    HBITMAP hBmp = LoadBitmap(hInst, (wchar_t*)IDB_BITMAP3);
    HDC hdcCover = CreateCompatibleDC(hdc);
    HGDIOBJ hPenDC = SelectObject(hdcCover, hBmp);

    for (int i = 0; i < ROW + 2; i++)
    {

        for (int j = 0; j < COL + 2; j++)
        {
            if (LOWORD(lParam) >= SCREENX + (i * map_x) && LOWORD(lParam) <= (SCREENX + (i * map_x)) + BMPX
                && HIWORD(lParam) >= SCREENY + (j * map_y) && HIWORD(lParam) <= (SCREENY + (j * map_y)) + BMPY
                && MapCover[i][j] == 1 && Map[i][j] != 0)
            {
                pointMine_f(hInst, hdc, hdcCover, i, j);
            }
        }
    }


    SelectObject(hdcCover, hPenDC);
    DeleteObject(hBmp);
    DeleteDC(hdcCover);

    ReleaseDC(hWnd, hdc);
}

//右键松开提示
void pointMine_f(HINSTANCE hInst, HDC hdc, HDC hdcCover, int x, int y)
{
    for (int i = x - 1; i <= x + 1; i++)
    {
        for (int j = y - 1; j <= y + 1; j++)
        {
            if ((i >= 0 && i < ROW && j >= 0 && j < COL) && MapCover[i][j] == 0 && MapMine[i][j] != 1)
            {
                BitBlt(hdc, SCREENX + (i * map_x), SCREENY + (j * map_y), BMPX, BMPY, hdcCover, 0, 0, SRCCOPY);

            }

        }
    }
}

//定时器
    case WM_TIMER:
    {
        TimeMine(hInst, hWnd);
    }
        break;

成品演示代码下载

下载方式

代码位置 (可以下载下去玩玩扫雷也不错)

游戏开发练习: 制作或复刻些许小游戏 - Gitee.com

下载方式 (把扫雷2.0文件下下来)

4cfdaa00526e4d96aeea30eeececb892.png

 下完后找到 x64/Debug 文件点进去

ba579c6dd2b245baa34fcde45a046468.png

 快捷方式(把快捷方式放到桌面就可以玩了)

016a8f2282204d1ca12a68c1d61916a1.png

 成品游玩视频

双击标雷 

20221114-201425

第一次写这么长文章的有些不好的地方多见谅

我是自学有些不好不对的还请多多建议

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值