MFC 扫雷

摘要:
花了两天时间做了一个MFC的扫雷,简单的实现了扫雷的功能,界面很草小毛病很多(比如标题。。Get(x,y)-˃IsOpen())16OpenMine(x,y);//嵌套打开17}18}19}20}再来说说MineView,这个类是单文档MFC程序的那个文档View,本来用基于对话框的可能更好,不过上次用对话框做了一个俄罗斯方块,这次换换口味。

花了两天时间做了一个MFC的扫雷,简单的实现了扫雷的功能,界面很草小毛病很多(比如标题。。),还望大家多多指正。

开发工具: VS2008

代码:https://files.cnblogs.com/GhostZCH/FindMine.rar

界面如下,红色的是标记,绿色的是还没有打开的各种,黄色的是已经打开的,红星是地雷(原谅程序的丑陋,唉,我也不是做美工的。。)

MFC 扫雷第1张MFC 扫雷第2张

MFC 扫雷第3张MFC 扫雷第4张

类图如下,主要是MineItem,MineGrid,MineView 三个类其他的基本都是自动生成的没做多大修改。MineItem和MineGird是逻辑上的格子单元和整个格子,游戏的主要逻辑操作都在MineGrid中完成,View至负责和用户交互,将用户消息翻译MineGrid可以理解的形式,并将MineGrid的数据实时的展现出来。两层式的程序结构也是我在小程序中屡试不爽的手段。MineItem的内容比较简单,这里只介绍一下MineGrid和MineViewd。

MFC 扫雷第5张

先说说MineGrid,MineGrid事实上是这个游戏的后台,所有的逻辑处理都在这个类中完成的。

定义了一个指针的指针用来存储数据:

MineItem **_grid;

初始化有点小麻烦,需要先初始化指针的指针在初始化每个指针,销毁的时候要反过来:

1     //初始化
2     _grid = new MineItem *[w*h];
3     for (int i=0;i<_height;i++)
4         for (int j=0;j<_width;j++)
5             _grid[i*_width+j] =  newMineItem();
6 
7     //析构
8     for (int i=0;i<_height;i++)
9         for (int j=0;j<_width;j++)
10 delete Get(i,j);
11 
12     delete _grid;
    // 已经标记取消标记,没有标记的进行标记,懒得写if else 了
    mineItem->IsMark(!mineItem->IsMark());

成片的打开有点麻烦,好像有人在网上求算法,其实也不是很难,嵌套的时候注意把已经打开的排除不要死循环就好了:

1 void MineGrid::OpenMine( int i,intj )
2 {
3     MineItem *mineItem =Get(i,j);
4     mineItem->IsOpen(true);//打开自己
5 
6     if(mineItem->Neighbour()==0)//周围没有雷打开周围的方格
7 {
8         for (int ii=-1;ii<=1;ii++)
9 {
10             for (int jj=-1;jj<=1;jj++)
11 {
12                 int x = ii+i;
13                 int y = jj+j;
14 
15                 if (x>=0&&x<_height&&y>=0&&y<_width&&!Get(x,y)->IsOpen())
16                     OpenMine(x,y);//嵌套打开
17 }
18 }
19 }
20 }

再来说说 MineView ,这个类是单文档MFC程序的那个文档View,本来用基于对话框的可能更好,不过上次用对话框做了一个俄罗斯方块,这次换换口味。

接受两个消息,作为打开格子和标记格子,传回后台处理逻辑,重绘处理的结果:

1 voidCFindMineView::OnLButtonUp(UINT nFlags, CPoint point)
2 {
3     inti,j;
4 
5 CView::OnLButtonUp(nFlags, point);
6 GetGirdLocation(point.x,point.y,i,j);
7 
8     _grid->Open(i,j);
9 Invalidate();
10 }
11 
12 voidCFindMineView::OnRButtonUp(UINT nFlags, CPoint point)
13 {
14     inti,j;
15 
16 CView::OnRButtonUp(nFlags, point);
17 GetGirdLocation(point.x,point.y,i,j);
18 
19     _grid->Mark(i,j);
20 Invalidate();
21 }

这个程序的难点在于绘画界面,MFC在OnDraw函数使用CDC绘制界面,略去了定义资源的步骤,这里第一步是定义用于填充的图片和内存CDC(和双缓存有关):

CBitmap _openBitMap;
    CBitmap _closeBitMap;
    CBitmap _markBitMap;
    CBitmap _mineBitMap;

    CDC _menDC ;

在首次使用前初始化这些数据:

1 void CFindMineView::LoadDC(CDC *pDC)
2 {
3     if (!_isLoadDc)//只能加载一次
4 {
5         _isLoadDc = true;
6 
7 _openBitMap.LoadBitmap(IDB_BTNDOWN);
8 _closeBitMap.LoadBitmap(IDB_BTNUP);
9 _markBitMap.LoadBitmap(IDB_BTNMARK);
10 _mineBitMap.LoadBitmap(IDB_BTNMINE);
11 
12         _menDC.CreateCompatibleDC(pDC);//每个dc这能创建一个关联的dc
13 }
14 }

每次OnDraw重绘真个界面,逐个的画出每个格子:

1 void CFindMineView::OnDraw(CDC*pDC)
2 {
3 LoadDC(pDC);
4 
5     for (int i=0;i<_grid->Height();i++)
6         for (int j=0;j<_grid->Width();j++)
7             DrawMine(i,j,pDC,_grid->Get(i,j));
8 }

自己写的DrawMine函数是这个类里面比较复杂的函数根据不同的数据用不同的画笔绘制一个小方格:

1 void CFindMineView::DrawMine( int i,int j,CDC* pdc,MineItem*mine )
2 {
3     if (mine->IsOpen())
4         if (mine->IsMine())
5           _menDC.SelectObject(&_mineBitMap);
6         else
7           _menDC.SelectObject(&_openBitMap);
8     else
9         if(mine->IsMark())
10              _menDC.SelectObject(&_markBitMap);
11         else
12             _menDC.SelectObject(&_closeBitMap);
13       
14       pdc->BitBlt(j*_wStep,i*_hStep,_wStep-1,_hStep-1,&_menDC,1,1,SRCCOPY);
15 
16       if (mine->IsOpen()&&!mine->IsMine()&&(mine->Neighbour()>0))
17 {
18 CString num;
19           num.Format(L"%d",mine->Neighbour());
20           pdc->TextOut(j*_wStep+19,i*_hStep+17,num);
21 }
22 }

差不多就这么多吧,欢迎大家多提意见。

免责声明:文章转载自《MFC 扫雷》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Assert中的静态方法系统综合实践 第5次实践作业下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【转】MFC 字体LOGFONT

Windows的字体LOGFONT   LOGFONT是Windows内部字体的逻辑结构,主要用于设置字体格式,其定义如下:typedef struct tagLOGFONTA{    LONG      lfHeight;    LONG      lfWidth;    LONG      lfEscapement;    LONG      lf...

30、深入浅出MFC学习笔记,多线程

一、基本概念 1、模块:一段可执行的程序(包括EXE和DLL),其程序代码、数据、资源被加载到内存中,由系统建置一个数据结构来管理它,就是一个模块。这里所说的数据结构,名为Module Database(MDB),其实就是PE格式中的PE表头,可以从WINNT.H 档中找到一个IMAGE_NT_HEADER 结构,就是它。 2、进程:就是一大堆拥有权(o...

MFC/VC++ UI界面美化技术

1. 工具: 1.1设备环境类: Windows下的绘图操作说到底就是DC操作。DC(Device Context设备环境)对象是一个抽象的作图环境,可能是对应屏幕,也可能是对应打印机或其它。这个环境是设备无关的,所以你在对不同的设备输出时只需 要使用不同的设备环境就行了,而作图方式可以完全不变。这也就是Windows的设备无关性。 MFC的CDC类封装了...

【转】VC 模式对话框和非模式对话框的创建,销毁和区别

原文网址:http://blog.csdn.net/mycaibo/article/details/6002151 VC 模式对话框和非模式对话框的创建,销毁和区别  在WIN32中,模式对话框的创建一般是使用DialogBox来进行创建的。而非模式对话框则是利用CreateWindow来创建的。在MFC或是WTL中,模式对话框一般是使用DoModal,...

VC++/MFC 最常用宏和指令

1、#include指令 包含指定的文件,最基本的最熟悉的指令,编程中不得不用,包含库文件用双尖括号,包含自定义头文件用双引号。 2、#define指令 预定义,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它本身并不在编译过程中进行,而是在预处理过程就已经完成了。 对于一个频繁使用的短小函数,在C语言中用宏定义...

MFC对话框和控件

对话框和控件 对话框是Windows应用程序中一种常用的资源,其主要功能是输出信息和接收用户的输入数据。控件是嵌入在对话框中或其它父窗口中的一个特殊的小窗口,它用于完成不同的输入、输出功能。对话框与控件关系密切,在每个对话框上一般都有一些控件,对话框依靠这些控件与用户进行信息的交互。 在MFC中,对话框的功能被封装在CDialog类中,而CDialog类是...