WINAPI实现简易扫雷游戏
1 //扫雷 2 #include <windows.h> 3 #include <windowsx.h> 4 #include <strsafe.h> 5 #include <time.h> 6 //格子区域大小(DIVISIONS * DIVISIONS) 7 #define DIVISIONS 20 8 //地雷数 9 #define MINECOUNT 40 10 11 //消息处理 12 LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 13 //写入地雷 14 void SetMine(int(*pChess)[DIVISIONS]); 15 //获取随机数 16 unsigned int GetRand(); 17 //判断胜利 18 bool Win(int(*pChess)[DIVISIONS], int *pNotClickCount, int *pClickCount); 19 //重置 20 void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS]); 21 22 int WINAPI WinMain( 23 HINSTANCE hInstance, // 当前实例句柄 24 HINSTANCE hPrevInstance,// 前一实例句柄 25 LPSTR lpCmdLine, // 指向命令行参数的指针 26 int nCmdShow // 窗口的显示方式 27 ) 28 { 29 HWND hWnd; 30 MSG msg; 31 WNDCLASS wndClass; 32 33 wndClass.cbClsExtra = 0; 34 wndClass.cbWndExtra = 0; 35 wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//画刷背景BLACK_PEN 36 wndClass.hCursor = LoadCursor(NULL, IDI_APPLICATION); 37 wndClass.hIcon = LoadIcon(NULL, IDC_ARROW); 38 wndClass.hInstance = hInstance; 39 wndClass.lpfnWndProc = DealMessage; 40 wndClass.lpszClassName = TEXT("MineSweeping"); 41 wndClass.lpszMenuName = NULL; 42 wndClass.style = CS_HREDRAW | CS_VREDRAW; 43 44 45 46 if (!RegisterClass(&wndClass)) 47 { 48 MessageBox(NULL, TEXT("注册类失败,请检查参数是否成功设置"), TEXT("提示"), MB_OK); 49 } 50 51 hWnd = CreateWindow(TEXT("MineSweeping"), // 窗口类名称 52 TEXT("扫雷"), // 窗口标题栏名称 53 WS_OVERLAPPEDWINDOW, // 窗口样式 54 CW_USEDEFAULT, // 窗口水平位置 55 CW_USEDEFAULT, // 窗口垂直位置 56 CW_USEDEFAULT, // 窗口宽度 57 CW_USEDEFAULT, // 窗口高度 58 NULL, // 父窗口句柄 59 NULL, // 窗口菜单句柄 60 hInstance, // 窗口实例句柄 61 NULL); // 窗口创建参数 62 if (!hWnd) // 新窗口创建失败 63 { 64 return FALSE; 65 } 66 67 ShowWindow(hWnd, SW_SHOWNORMAL); 68 UpdateWindow(hWnd); 69 70 while (GetMessage(&msg, NULL, 0, 0)) 71 { 72 TranslateMessage(&msg); 73 DispatchMessage(&msg); 74 } 75 76 return msg.wParam; 77 } 78 79 80 LRESULT CALLBACK DealMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 81 { 82 //初始化要用到的变量 83 HDC hdc; 84 PAINTSTRUCT ps; 85 RECT rect; 86 HBRUSH hBrush, hOldBrush; 87 TEXTMETRIC tm; 88 static int cxChar,cxCaps,cyChar; 89 90 //输出整形用的缓冲区 91 TCHAR szBuffer[128]; 92 size_t iTarget; 93 94 //地雷以及点击后雷个数存储区 95 static int iChess[DIVISIONS][DIVISIONS]; 96 int(*pChess)[DIVISIONS] = iChess; 97 //点击后记录点击事件存储区 98 static int iClick[DIVISIONS][DIVISIONS]; 99 int(*pClick)[DIVISIONS] = iClick; 100 101 //pSize:当前一个格子宽高 102 //p:通用 103 static POINT pSize = { 0,0 }, p; 104 105 //未点击的格子 106 int iNotClickCount; 107 //已经点击的格子 108 int iClickCount; 109 110 switch (uMsg) 111 { 112 case WM_CREATE: 113 hdc = GetDC(hWnd); 114 //初始化 115 Reset(hWnd, pChess, pClick); 116 //获取字体高度 117 GetTextMetrics(hdc, &tm); 118 cyChar = tm.tmHeight + tm.tmExternalLeading; 119 //平均宽度 120 cxChar = tm.tmAveCharWidth; 121 //判断是否等宽字体 122 cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2; 123 124 ReleaseDC(hWnd, hdc); 125 return 0; 126 case WM_KEYDOWN: 127 //在没有鼠标的情况下,键盘模拟鼠标操作 128 ShowCursor(false); 129 GetCursorPos(&p); 130 ScreenToClient(hWnd, &p); 131 p.x = max(0, min(DIVISIONS - 1, p.x / pSize.x)); 132 p.y = max(0, min(DIVISIONS - 1, p.y / pSize.y)); 133 134 switch (wParam) 135 { 136 case VK_UP: 137 p.y = max(0, p.y - 1); 138 break; 139 case VK_DOWN: 140 p.y = min(DIVISIONS - 1, p.y + 1); 141 break; 142 case VK_LEFT: 143 p.x = max(0, p.x - 1); 144 break; 145 case VK_RIGHT: 146 p.x = min(DIVISIONS - 1, p.x + 1); 147 break; 148 case VK_HOME: 149 p.x = p.y = 0; 150 break; 151 case VK_END: 152 p.x = p.y = DIVISIONS - 1; 153 break; 154 case VK_RETURN: 155 case VK_SPACE: 156 SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(p.x * pSize.x, p.y * pSize.y)); 157 break; 158 } 159 p.x = (p.x * pSize.x) + (pSize.x / 2); 160 p.y = (p.y * pSize.y) + (pSize.y / 2); 161 162 ClientToScreen(hWnd, &p); 163 SetCursorPos(p.x, p.y); 164 ShowCursor(true); 165 return 0; 166 case WM_SIZE: 167 //pSize每个格子大小,X宽,Y高 168 pSize.x = LOWORD(lParam) / DIVISIONS; 169 pSize.y = HIWORD(lParam) / DIVISIONS; 170 return 0; 171 case WM_LBUTTONDOWN: 172 p.x = GET_X_LPARAM(lParam) / pSize.x; 173 p.y = GET_Y_LPARAM(lParam) / pSize.y; 174 if (p.x >= DIVISIONS || p.y >= DIVISIONS) 175 { 176 MessageBeep(0); 177 return 0; 178 } 179 switch (iClick[p.x][p.y]) 180 { 181 case 1: 182 MessageBeep(0); 183 return 0; 184 case 2: 185 MessageBeep(0); 186 return 0; 187 } 188 //判断是否点击到了雷 189 if (iChess[p.x][p.y] == -1) 190 { 191 if (MessageBox(hWnd, TEXT("你踩到地雷了!"), TEXT("boom"), MB_OK) == IDOK) 192 { 193 Reset(hWnd,pChess, pClick); 194 InvalidateRect(hWnd, NULL, true); 195 } 196 } 197 else 198 { 199 //当前位置修改为点击过 200 iClick[p.x][p.y] = 1; 201 //判断是否胜利 202 if (Win(pClick, &iNotClickCount, &iClickCount)) 203 { 204 if (MessageBox(hWnd, TEXT("you win!"), TEXT("wow"), MB_OK) == IDOK) 205 { 206 Reset(hWnd,pChess, pClick); 207 } 208 } 209 //标题显示信息 210 StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("当前已经翻出的区域数%d,剩余区域数%d"), iClickCount, iNotClickCount); 211 StringCchLength(szBuffer, sizeof(szBuffer), &iTarget); 212 SetWindowText(hWnd, szBuffer); 213 //计算当前点击位置附近雷数 214 for (int x = -1; x <= 1; x++) 215 { 216 for (int y = -1; y <= 1; y++) 217 { 218 //超出客户区的格子不计算 219 if (p.x + x >= 0 && p.x + x < DIVISIONS && p.y + y >= 0 && p.y + y < DIVISIONS) 220 { 221 //当前格子不计算 222 if (x != 0 || y != 0) { 223 if (iChess[p.x + x][p.y + y] == -1) 224 { 225 iChess[p.x][p.y]++; 226 } 227 } 228 } 229 } 230 } 231 } 232 //重绘格子 233 rect.left = p.x * pSize.x; 234 rect.top = p.y * pSize.y; 235 rect.right = (p.x + 1) * pSize.x; 236 rect.bottom = (p.y + 1) * pSize.y; 237 InvalidateRect(hWnd, &rect, true); 238 return 0; 239 case WM_RBUTTONDOWN: 240 p.x = GET_X_LPARAM(lParam) / pSize.x; 241 p.y = GET_Y_LPARAM(lParam) / pSize.y; 242 if (p.x >= DIVISIONS || p.y >= DIVISIONS) 243 { 244 MessageBeep(0); 245 return 0; 246 } 247 //当前格子标记地雷状态切换 248 switch (iClick[p.x][p.y]) 249 { 250 case 0: 251 iClick[p.x][p.y] = 2; 252 break; 253 case 2: 254 iClick[p.x][p.y] = 0; 255 break; 256 default: 257 MessageBeep(0); 258 return 0; 259 } 260 //重绘格子 261 rect.left = p.x * pSize.x; 262 rect.top = p.y * pSize.y; 263 rect.right = (p.x + 1) * pSize.x; 264 rect.bottom = (p.y + 1) * pSize.y; 265 InvalidateRect(hWnd, NULL, true); 266 return 0; 267 case WM_MOUSEMOVE: 268 //鼠标超出扫雷区域鼠标禁止点击 269 p.x = GET_X_LPARAM(lParam) / pSize.x; 270 p.y = GET_Y_LPARAM(lParam) / pSize.y; 271 if (p.x >= DIVISIONS || p.y >= DIVISIONS) 272 { 273 SetCursor(LoadCursor(NULL, IDC_NO)); 274 } 275 else 276 { 277 SetCursor(LoadCursor(NULL, IDC_ARROW)); 278 } 279 return 0; 280 case WM_PAINT: 281 hdc = BeginPaint(hWnd, &ps); 282 //扫雷棋盘绘画 283 for (int i = 1; i < DIVISIONS; i++) 284 { 285 MoveToEx(hdc, pSize.x * i, 0, NULL); 286 LineTo(hdc, pSize.x * i, pSize.y * DIVISIONS); 287 288 MoveToEx(hdc, 0, pSize.y * i, NULL); 289 LineTo(hdc, pSize.x * DIVISIONS, pSize.y * i); 290 } 291 //扫雷点击绘画 292 for (int x = 0; x < DIVISIONS; x++) 293 { 294 for (int y = 0; y < DIVISIONS; y++) 295 { 296 //0:未开过的格子,1:开过的格子,2:标记过的格子 297 switch (iClick[x][y]) 298 { 299 case 1: 300 //每个格子背景变成灰色 301 hBrush = CreateSolidBrush(RGB(220, 220, 220));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 302 Rectangle(hdc, x * pSize.x, y * pSize.y, (x + 1) * pSize.x, (y + 1) * pSize.y); 303 SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush); 304 305 //当前格子写入地雷数 306 //地雷数颜色随地雷数改变 307 switch (iChess[x][y]) 308 { 309 case 0: 310 SetTextColor(hdc, RGB(0, 0, 0)); break; 311 case 1: 312 SetTextColor(hdc, RGB(0, 0, 255)); break; 313 case 2: 314 SetTextColor(hdc, RGB(144, 238, 144)); break; 315 case 3: 316 SetTextColor(hdc, RGB(255, 0, 0)); break; 317 case 4: 318 SetTextColor(hdc, RGB(255, 0, 255)); break; 319 case 5: 320 SetTextColor(hdc, RGB(139, 0, 0)); break; 321 case 6: 322 SetTextColor(hdc, RGB(0, 100, 0)); break; 323 } 324 SetBkMode(hdc, TRANSPARENT); 325 StringCchPrintf(szBuffer, sizeof(szBuffer), TEXT("%d"), iChess[x][y]); 326 StringCchLength(szBuffer, sizeof(szBuffer), &iTarget); 327 TextOut(hdc, (x * pSize.x) + (pSize.x / 2) - (cxChar / 2), (y * pSize.y) + (pSize.y / 2) - (cyChar / 2), szBuffer, iTarget); 328 break; 329 case 2: 330 hBrush = CreateSolidBrush(RGB(255, 0, 0));hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 331 //画一个标记的旗子 332 MoveToEx(hdc, (x * pSize.x) + (pSize.x / 2), (y * pSize.y) + (pSize.y / 2) - 5, NULL); 333 LineTo(hdc, (x * pSize.x) + (pSize.x / 2), (y * pSize.y) + (pSize.y / 2) + 5); 334 335 Rectangle(hdc, (x * pSize.x) + (pSize.x / 2), (y * pSize.y) + (pSize.y / 2) - 5, (x * pSize.x) + (pSize.x / 2) + 10, (y * pSize.y) + (pSize.y / 2)); 336 337 MoveToEx(hdc, (x * pSize.x) + (pSize.x / 2) - 3, (y * pSize.y) + (pSize.y / 2) + 5, NULL); 338 LineTo(hdc, (x * pSize.x) + (pSize.x / 2) + 3, (y * pSize.y) + (pSize.y / 2) + 5); 339 340 SelectObject(hdc, hOldBrush);DeleteObject(hBrush);DeleteObject(hOldBrush); 341 break; 342 } 343 344 } 345 } 346 347 EndPaint(hWnd, &ps); 348 return 0; 349 case WM_DESTROY: 350 PostQuitMessage(0); 351 break; 352 default: 353 return DefWindowProc(hWnd, uMsg, wParam, lParam); 354 } 355 return 0; 356 } 357 //产生随机数 358 unsigned int GetRand() 359 { 360 int r = rand(); 361 r = r % DIVISIONS; 362 return r; 363 } 364 365 //写入地雷 366 void SetMine(int(*pChess)[DIVISIONS]) 367 { 368 POINT pPoint; 369 for (int i = 0; i < MINECOUNT; i++) 370 { 371 while (true) 372 { 373 pPoint.x = GetRand(); 374 pPoint.y = GetRand(); 375 if (pChess[pPoint.x][pPoint.y] != -1) 376 { 377 pChess[pPoint.x][pPoint.y] = -1; 378 break; 379 } 380 } 381 } 382 return; 383 } 384 385 //判断获胜 386 bool Win(int(*pChess)[DIVISIONS],int *pNotClickCount,int *pClickCount) 387 { 388 int i = 0; 389 for (int x = 0; x < DIVISIONS; x++) 390 { 391 for (int y = 0; y < DIVISIONS; y++) 392 { 393 if (pChess[x][y] == 0|| pChess[x][y] == 2) 394 { 395 i++; 396 } 397 } 398 } 399 *pNotClickCount = i; 400 *pClickCount = (DIVISIONS * DIVISIONS) - i; 401 if (i - MINECOUNT == 0) 402 { 403 return true; 404 } 405 return false; 406 } 407 408 //重置 409 void Reset(HWND hWnd,int(*pChess)[DIVISIONS], int(*pClick)[DIVISIONS]) 410 { 411 //防止随机数重复 412 srand((unsigned(time(NULL)))); 413 SetCursor(LoadCursor(NULL, IDC_WAIT)); 414 for (int x = 0; x < DIVISIONS; x++) 415 { 416 for (int y = 0; y < DIVISIONS; y++) 417 { 418 pChess[x][y] = 0; 419 pClick[x][y] = 0; 420 } 421 } 422 //memset(pChess, 0, sizeof(pChess)); 423 //memset(pClick, 0, sizeof(pClick)); 424 SetMine(pChess); 425 SetCursor(LoadCursor(NULL, IDC_ARROW)); 426 InvalidateRect(hWnd, NULL, true); 427 return; 428 }
转载于:https://www.cnblogs.com/weijunyu/p/10330328.html
WINAPI实现简易扫雷游戏相关推荐
- php游戏实例,php实现的简易扫雷游戏实例_PHP
本文实例讲述了php实现的简易扫雷游戏.分享给大家供大家参考.具体如下: = 0 && $j - 1 >= 0 && $data["data" ...
- C语言实现简易扫雷游戏
本文所讲述的主要是如何用C语言的数组知识,实现简易的扫雷游戏. 若只需工程代码不需详情解释,可直接跳到末尾,在末尾会把代码全部展示出来. 首先要明白扫雷(初级)的游戏机制: 1.在9* ...
- 简易扫雷游戏c语言程序,C++实现简单的扫雷游戏(控制台版)
C++新手的代码,请各位多包涵. 用C++写的一个简单的控制台版扫雷游戏.玩家通过输入方块的坐标来翻开方块. 只是一个雏形,能够让玩家执行翻开方块的操作并且判断输赢,还未添加标记方块.游戏菜单.记录游 ...
- C语言实现简易扫雷游戏(最后附完整码源)
首先我们在test函数中写一个简单的do while循环,如下: void test() {srand((unsigned int)time(NULL));int input = 0;do{menu( ...
- Java语言实现的扫雷游戏(二)
在上一篇文章中,我们已经将扫雷的绘制了方格阵列并随机分配了炸弹的位置,接下来我们要将阵列全部覆盖上按钮.因为我们要通过按钮来获知当前方格的坐标,所以简单的Button按钮还无法满足我们的要求,所以,我 ...
- 扫雷游戏 (20 分)
无聊的老 H 最近迷上了扫雷游戏,但是真正的扫雷游戏老 H 还不会玩,只能尝试更为简单 且纯粹依靠运气的扫雷游戏 简易扫雷游戏规则: 给定扫雷的游戏棋盘是一个 N * N 的矩阵,且棋盘中只有 X 和 ...
- C语言扫雷游戏(简易版)
前言 经过学习数组.函数.循环语句.选择语句等C语言的一些基础知识后,我想借助编写扫雷小游戏来对所学知识进行一个巩固.游戏只会实现一些基本的功能,展开.标记雷.取消雷等不实现(还不会). 1.游戏编写 ...
- c++简易版扫雷游戏
c++简易版扫雷游戏,代码如下: #include<iostream> #include<cstdlib> #include<time.h> using names ...
- 利用java开发简易版扫雷游戏
1.简介 学了几周的Java,闲来无事,写个乞丐版的扫雷,加强一下Java基础知识. 2.编写过程 编写这个游戏,一共经历了三个阶段,编写了三个版本的游戏代码. 第一版:完成了扫雷游戏的基本雏形,实现 ...
- 【C语言】简易版扫雷游戏(play game)
目录 扫雷游戏
最新文章
- android mac测试地址,android获取有线网的Mac地址
- springmvc如何访问静态文件,例如jpg,js,css
- odoo 自定义视图_如何使用Windows的五个模板自定义文件夹视图
- Logstash 命令行参数
- Tr A(矩阵快速幂)
- LeetCode 1844. 将所有数字用字符替换
- Memcached在Windows7上的安装问题
- linux之SQL语句简明教程---CONCATENATE
- 计算机电源的瓦数是什么,电脑的电源功率大小有区别吗?对电脑有什么影响吗?...
- AotucCrawler 快速爬取美女图片
- java 生成水印_Java实现图片生成水印
- C学习笔记之---八皇后算法
- 【国信安实训】——文件上传漏洞
- C# 浅谈基于Wpf下的MVVM模式的设计思想
- MAC OS的HOME和END
- 日程规划软件哪个好 2022日程规划便签APP下载
- 如何正确理解店宝宝软件
- C1-见习工程师(计算机通识)
- GPL与BSD许可证的区别
- SLAM 入门之《SLAM 14讲》笔记
热门文章
- 实验项目1matlab熟练使用,数字信号处理实验一 熟悉matlab环境.doc
- 永磁同步电机基于模型预测控制(MPC)电流环和 基于二阶滑模控制(ST SMC)电流环以及 基于PI控制电流环三合一模型
- 第二十天学Python:标准库(4)sys和time、可执行文件
- C语言求100到500的所有质数,每10个数字一行打印
- 期权合约的几个影响因素
- java获取前一年前一月前一周时间Date类型数据
- 一小只支付接口的自动化
- asr1009查看接口光衰_MA5680基本查询命令.doc
- 就业内推 | 15薪,上市公司、金融机构诚聘系统运维工程师
- 发明专利申请时间多长?