MFC 扫雷.docx

上传人:牧羊曲112 文档编号:3161442 上传时间:2023-03-11 格式:DOCX 页数:22 大小:44.80KB
返回 下载 相关 举报
MFC 扫雷.docx_第1页
第1页 / 共22页
MFC 扫雷.docx_第2页
第2页 / 共22页
MFC 扫雷.docx_第3页
第3页 / 共22页
MFC 扫雷.docx_第4页
第4页 / 共22页
MFC 扫雷.docx_第5页
第5页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《MFC 扫雷.docx》由会员分享,可在线阅读,更多相关《MFC 扫雷.docx(22页珍藏版)》请在三一办公上搜索。

1、MFC 扫雷一个多月的VC+学习很苦闷!总想着找点让人兴奋的东西.要不然很难在继续学下去了,今天在VC编程论坛里看到一位高手写的东西,恍然大悟!用VC编写游戏.以下是他在书中的几个例子,发给大家一起学习. 第二章 扫雷 1 游戏实现 扫雷,是附带在Window里面的游戏,是个简单的游戏。因此我们就从扫雷开始我们的游戏旅程。很多人都玩过这个游戏,只是不知道怎么用程序实现。不过还有人不知道怎么玩,下面就先说说游戏的规则: 开始:按左键开始游戏,按按钮或菜单重新开始。 左键:按下时,是雷则结束,非雷则显示数字。 数字:代表此数字周围一圈八格中雷的个数。 右键:奇次按下表示雷,偶数按下表示对上次的否定

2、。 结束:左键按到雷结束,找出全部雷结束。 接下来就该介绍游戏的编程过程了。不过要先交代一下一些内容。 添加位图。 添加全局变量。 画初始界面。 添加函数。 为什么要按这种次序呢?因为我们在画初始界面时,可能要用到位图或变量,而变量的定义又可能要对位图进行定义。这样的步骤的好处还有:在做一步之后都可以运行,有错就改,无错就做下一步。 上图是扫雷的一个画面。 下面就一步一步地演示,以编程的思路进行,当然,由于编程过程中有一些函数中的代码是分成两三次写的,我们就不重复,全部代码在第一次讲到时列出,而后面讲到时就只是提一下。 新建单文档工程2_1。 2 资源编辑 添加位图: 前十二幅是在雷区的,后四

3、幅是按钮。为了便于加载,必须各自保证其连续性。另外,为什么不添加一个按钮而用位图呢?是因为即使我们添加了按钮也要添加四幅位图! 位图的ID号: 按扭位图: 30*30 IDB_ANNIU1、IDB_ANNIU 2、IDB_ANNIU3、 IDB_ANNIU4 雷区位图: 14*14 ID号按下图依次为:IDB_BITMAP14。IDB_BITMAP25 位图:下图。 3 变量函数 定义新类: 对于雷,我们是单独定义一个类,这样有利于程序的操作。 class Lei public: /显示哪一个位图 intweitu; /这个位置相应的值 intshumu; ; 并有如下规定: 视图类变量: 接

4、着是在View类添加变量和函数: /剩下雷数 intleftnum; /雷数 intleinum; /结束 intjieshu; /计时 short second; /开始计时 intsecondstart; /位图数组 CBitmapm_Bitmap12; /按扭位图数组 CBitmapm_anniu4; /雷区行数 intm_RowCount; /雷区列数 intm_ColCount; /最大雷区 Lei lei5050; /这个位置周围雷数为0 voidleizero; /计时器函数 afx_msg void OnTimer(UINT nIDEvent); /鼠标按下左键 afx_msg

5、 void OnLButtonDown(UINT nFlags, CPoint point); /鼠标按下右键 afx_msg void OnRButtonDown(UINT nFlags, CPoint point); /初始化函数 afx_msgintOnCreate(LPCREATESTRUCT lpCreateStruct); /鼠标左键松开 afx_msg void OnLButtonUp(UINT nFlags, CPoint point); 4 具体实现 删去状态栏和工具栏: 开始执行程序,就能见到一个有状态栏和工具栏的大的单文档,与上图不同,所以我们第一步就是整理框架: 打开下

6、面函数,把里面的一些语句去掉。如下所示: intCMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct) if (CFrameWnd:OnCreate(lpCreateStruct) = -1) return -1; /* if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) | !m_wndToolBar.LoadT

7、oolBar(IDR_MAINFRAME) TRACE0(Failed to create toolbarn); return -1; / fail to create if (!m_wndStatusBar.Create(this) | !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT) TRACE0(Failed to create status barn); return -1; / fail to create / TODO: Delete these three lines if you

8、dont want the toolbar to / bedockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); */ return 0; 设置窗口大小: 运行附加的代码,还能看到扫雷游戏的框架是不能调大小的,而且总是显示在最前面,这又是怎么实现的呢? 在下面函数里添加语句,你能说出前三句是什么意思吗?注释已经被我去掉了,如果不知道,不如按一下F1。 BOOL CMainFrame:PreCreateWindow(CREA

9、TESTRUCT&cs) if( !CFrameWnd:PreCreateWindow(cs) ) return FALSE; / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST; / cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;/; /设置窗口大小:400*340 cs.cx=400; cs.cy=340; return TRUE; 构造函数: 由于

10、构造函数是程序运行时就执行的,所以,除了对变量赋值之外,我们还可以把游戏的核心结构即内部数组赋值:先是把全部格子的位图和雷数赋值为0,然后调用随机函数按指定雷数赋值为-1,最后把不是雷的格子的雷数赋值为相应的值。 CMy2_1View:CMy2_1View / TODO: add construction code here for(int ii=0;ii16;ii+) m_Bitmapii.LoadBitmap(IDB_BITMAP14+ii); for(intjj=0;jj4;jj+) m_anniujj.LoadBitmap(IDB_ANNIU1+jj); /计时 second=0; /

11、1时开始计时 secondstart=0; /行数 m_RowCount=25; /列数 m_ColCount=16; /雷数 leinum=80; /剩余雷数 leftnum=leinum; /jieshu=1时停止 jieshu=0; intaa=0; /初始化为0 for(int i=0;im_RowCount;i+) for(int j=0;jm_ColCount;j+) leiij.shumu=0; leiij.weitu=0; /获取当前时间 CTime time=GetCurrentTime; int s; /获取秒数 s=time.GetSecond; /设置40个雷 do /

12、以当前秒数为产生随机算法 int k=(rand*s)%m_RowCount; int l=(rand*s)%m_ColCount; /为了避免一个位置同时算两个雷 /只允许当前位置不是雷时赋值为雷 if(leikl.shumu!=-1) leikl.shumu=-1; aa+; while(aa!=leinum); /给方格赋值,计算雷数 for(int a=0;am_RowCount;a+) for(int b=0;bm_ColCount;b+) if(leiab.shumu=0) for(int c=a-1;ca+2;c+) for(int d=b-1;d=0&c=0&dFillRect

13、(myrect1,&mybrush1); /画黑框 CBrushmybrush; mybrush.CreateSolidBrush(RGB(0,0,0); CRectmyrect(20,10,70,40); pDC-FillRect(myrect,&mybrush); CRectmyrect2(325,10,375,40); pDC-FillRect(myrect2,&mybrush); CPenmypen; CPen*myoldPen; mypen.CreatePen(PS_SOLID,2,RGB(255,255,255); myoldPen=pDC-SelectObject(&mypen)

14、; /画黑框的白线 pDC-MoveTo(20,40); pDC-LineTo(70,40); pDC-LineTo(70,10); pDC-MoveTo(325,40); pDC-LineTo(375,40); pDC-LineTo(375,10); /画雷区边线 /左上角是白线,右下角是黑线,以显示立体感 for(int i=0;im_RowCount;i+) for(int j=0;jMoveTo(10+i*15,50+j*15+14); pDC-LineTo(10+i*15,50+j*15); pDC-LineTo(10+i*15+14,50+j*15); pDC-SelectObje

15、ct(myoldPen); CPen mypen2; CPen*myoldPen2; mypen2.CreatePen(PS_SOLID,1,RGB(0,0,0); myoldPen2=pDC-SelectObject(&mypen2); for(int ii=0;iim_RowCount;ii+) for(intjj=0;jjMoveTo(10+ii*15,50+jj*15+14); pDC-LineTo(10+ii*15+14,50+jj*15+14); pDC-LineTo(10+ii*15+14,50+jj*15); pDC-SelectObject(myoldPen2); CDC D

16、c; if(Dc.CreateCompatibleDC(pDC)=FALSE) AfxMessageBox(Cant create DC); / Dc.SelectObject(m_anniu0); pDC-BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); /显示按钮 判断显示什么位图 /weitu=1已按下的数字区 /weitu=2显示旗 /weitu=3显示问号 for(int a=0;am_RowCount;a+) for(int b=0;bBitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); if(leiab.w

17、eitu=2) Dc.SelectObject(m_Bitmap9); pDC-BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); if(leiab.weitu=3) Dc.SelectObject(m_Bitmap10); pDC-BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY); /结束 if(jieshu=1&leiab.shumu=-1) Dc.SelectObject(m_Bitmap11); pDC-BitBlt(a*15+10,b*15+50,160,160,&Dc,0,0,SRCCOPY

18、); Dc.SelectObject(m_anniu3); pDC-BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); /显示黑框里的数字 intnOldDC=pDC-SaveDC; pDC-SetTextColor(RGB(255,0,0); pDC-SetBkColor(RGB(0,0,0); CFont font; if(0=font.CreatePointFont(160,Comic Sans MS) AfxMessageBox(Cant Create Font); pDC-SelectObject(&font); CStringstr; /利用判断显示位数

19、,不够三位前面加0 if(leftnumTextOut(25,10,str); if(second10) str.Format(00%d,second); else if(secondTextOut(330,10,str); pDC-RestoreDC(nOldDC); 运行一下,外观已经出来了,只是还不能玩。那我们就来添加一些功能函数,使它可以玩。 当然,如果你对程序已经有一定的经验的话,你就会指出上面的函数太长了。这并不太符合我们编程的要求。我们编程有一个讲究,就是尽量使函数的代码少,一般为一页左右,便于查看。那么,我们可以把上面的函数细分为几个小函数,然后在这个函数里面分别调用。 按下鼠

20、标左键: 用if语句判断,如果在按钮上面,则显示按钮按下位图;如果在扫雷区,先把按钮位图改为张口位图,再判断按下的是否是雷,是就结束,重画,以显示所有的雷;否则,重画相应格子以显示数字。 void CMy2_1View:OnLButtonDown(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call default /获取指针pdc CDC *pDC=GetDC; CDC Dc; if(Dc.CreateCompatibleDC(pDC)=FALSE) AfxMessageBox(Ca

21、nt create DC); /显示按下按钮 if(point.x180&point.x10&point.yBitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); if(point.x=10)&(point.x=50)&(point.yBitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); / secondstart为1时计时有效 secondstart=1; /鼠标坐标转换为数组坐标 int a=(point.x-10)/15; int b=(point.y-50)/15; if(leiab.weitu=0|leiab.weitu=3) if(

22、leiab.shumu=-1) jieshu=1; /结束时,释放Timer KillTimer(1); /重画,因为这次重画将显示全部的雷, /不能用部分重画 Invalidate; else leiab.weitu=1; CRectrect; rect.left=a*15+10; rect.right=a*15+25; rect.top=b*15+50; rect.bottom=b*15+65; InvalidateRect(&rect); CView:OnLButtonDown(nFlags, point); 如果你现在运行的话,你会发现按下按钮时并不还原,这就涉及到鼠标函数:OnLBu

23、ttonUp(UINT nFlags, CPoint point) 松开鼠标左键: 松开左键时,显示按钮没有按下的位图;再判断,如果结束,就要显示失败的位图;另外,如果是在按钮上松开按钮,即表示我们已经按下了重新开始的按钮,必须调用重新开始函数OnStart。 由于OnStart函数是与菜单里的开始共有的,此处先保留不说,若有必要运行,可以先去掉最后两行。 void CMy2_1View:OnLButtonUp(UINT nFlags, CPoint point) / TODO: Add your message handler code here and/or call default CD

24、C *pDC=GetDC; CDC Dc; if(Dc.CreateCompatibleDC(pDC)=FALSE) AfxMessageBox(Cant create DC); /显示按钮 Dc.SelectObject(m_anniu0); pDC-BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); if(jieshu=1) /显示按扭位图 Dc.SelectObject(m_anniu2); pDC-BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY); /如果按下的是按扭,重新开始 if(point.x180&point.x10&po

25、int.y=10)&(point.x=50)&(point.y=290) int a=(point.x-10)/15; int b=(point.y-50)/15; if(leiab.weitu=0|leiab.weitu=3) leiab.weitu=2; leftnum-; else if(leiab.weitu=2) leiab.weitu=3; leftnum+; /重画剩下雷数 CRect rect2; rect2.left=20; rect2.right=70; rect2.top=10; rect2.bottom=40; InvalidateRect(&rect2); /重画打击

26、格子 CRectrect; rect.left=a*15+10; rect.right=a*15+25; rect.top=b*15+50; rect.bottom=b*15+65; InvalidateRect(&rect); CView:OnRButtonDown(nFlags, point); 显示没有雷的区域: 运行,玩一下,你会发现当按下的是一个周围没有雷的格子是它并不会象Window里面的扫雷游戏一样显示它周围的格子雷数。怎么实现呢? 添加一个如下函数: /扫描,如果是已经被按下且雷数为0,显示它周围的八个格,并重画 void CMy2_1View:leizero for(int i=0;im_RowCount;i+) for(int j=0;jm_ColCount;j+) if(leiij.shumu=0&leiij.weitu=1) for(int n=i-1;ni+2;n+) for(int m=j-1;m=0&n=0&mm_ColCount) if(leinm.shumu!=-1&leinm.weitu=0) leinm.weitu=1; CRectrect; rect.left=n*15+10; rect.right=n*15+25; rect.top=m*15+50; rect.bottom=m*15+65;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号