已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第二章 第二章 扫雷1 1 游戏实现扫雷,是附带在Window里面的游戏,是个简单的游戏。因此我们就从扫雷开始我们的游戏旅程。很多人都玩过这个游戏,只是不知道怎么用程序实现。不过还有人不知道怎么玩,下面就先说说游戏的规则: 开始:按左键开始游戏,按按钮或菜单重新开始。左键:按下时,是雷则结束,非雷则显示数字。数字:代表此数字周围一圈八格中雷的个数。右键:奇次按下表示雷,偶数按下表示对上次的否定。结束:左键按到雷结束,找出全部雷结束。接下来就该介绍游戏的编程过程了。不过要先交代一下一些内容。 添加位图。 添加全局变量。 画初始界面。 添加函数。为什么要按这种次序呢?因为我们在画初始界面时,可能要用到位图或变量,而变量的定义又可能要对位图进行定义。这样的步骤的好处还有:在做一步之后都可以运行,有错就改,无错就做下一步。上图是扫雷的一个画面。下面就一步一步地演示,以编程的思路进行,当然,由于编程过程中有一些函数中的代码是分成两三次写的,我们就不重复,全部代码在第一次讲到时列出,而后面讲到时就只是提一下。新建单文档工程2_1。2 2 资源编辑添加位图:前十二幅是在雷区的,后四幅是按钮。为了便于加载,必须各自保证其连续性。另外,为什么不添加一个按钮而用位图呢?是因为即使我们添加了按钮也要添加四幅位图!位图的ID号:按扭位图:30*30 IDB_ANNIU1、IDB_ANNIU 2、IDB_ANNIU3、 IDB_ANNIU4雷区位图:14*14ID号按下图依次为:IDB_BITMAP14。IDB_BITMAP25位图:下图(图2-1)。 3 3 变量函数定义新类:对于雷,我们是单独定义一个类,这样有利于程序的操作。 class Leipublic: /显示哪一个位图int weitu; /这个位置相应的值int shumu;并有如下规定(图2-2): 视图类变量: 接着是在View类添加变量和函数:/剩下雷数int leftnum; /雷数int leinum;/结束int jieshu;/计时short second; /开始计时int secondstart; /位图数组CBitmap m_Bitmap12;/按扭位图数组CBitmap m_anniu4;/雷区行数int m_RowCount; /雷区列数int m_ColCount; /最大雷区Lei lei5050; /这个位置周围雷数为0void leizero(); /计时器函数afx_msg void OnTimer(UINT nIDEvent); /鼠标按下左键afx_msg void OnLButtonDown(UINT nFlags, CPoint point);/鼠标按下右键afx_msg void OnRButtonDown(UINT nFlags, CPoint point); /初始化函数afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); /鼠标左键松开afx_msg void OnLButtonUp(UINT nFlags, CPoint point);4 4 具体实现删去状态栏和工具栏:开始执行程序,就能见到一个有状态栏和工具栏的大的单文档,与上图不同,所以我们第一步就是整理框架:打开下面函数,把里面的一些语句去掉。如下所示: int CMainFrame: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.LoadToolBar(IDR_MAINFRAME)TRACE0(Failed to create toolbarn);return -1; / fail to createif (!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 dont want the toolbar to/ be dockablem_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);*/return 0; 设置窗口大小:运行附加的代码,还能看到扫雷游戏的框架是不能调大小的,而且总是显示在最前面,这又是怎么实现的呢? 在下面函数里添加语句,你能说出前三句是什么意思吗?注释已经被我去掉了,如果不知道,不如按一下F1。 BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs)if( !CFrameWnd:PreCreateWindow(cs) )return FALSE;/ TODO: Modify the Window class or styles here by modifying/ the CREATESTRUCT cscs.dwExStyle=cs.dwExStyle|WS_EX_TOPMOST;/cs.style=WS_SYSMENU|WS_OVERLAPPED|WS_MINIMIZEBOX;/; /设置窗口大小:400*340cs.cx=400;cs.cy=340; return TRUE; 构造函数:由于构造函数是程序运行时就执行的,所以,除了对变量赋值之外,我们还可以把游戏的核心结构即内部数组赋值:先是把全部格子的位图和雷数赋值为0,然后调用随机函数按指定雷数赋值为-1,最后把不是雷的格子的雷数赋值为相应的值。CMy2_1View:CMy2_1View()/ TODO: add construction code herefor(int ii=0;ii16;ii+)m_Bitmapii.LoadBitmap(IDB_BITMAP14+ii); for(int jj=0;jj4;jj+)m_anniujj.LoadBitmap(IDB_ANNIU1+jj); /计时second=0; /1时开始计时secondstart=0; /行数m_RowCount=25; /列数m_ColCount=16; /雷数 leinum=80; /剩余雷数leftnum=leinum; /jieshu=1时停止jieshu=0; int aa=0;/初始化为0for(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/以当前秒数为产生随机算法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(myrect1,&mybrush1); /画黑框CBrush mybrush; mybrush.CreateSolidBrush(RGB(0,0,0); CRect myrect(20,10,70,40); pDC-FillRect(myrect,&mybrush);CRect myrect2(325,10,375,40); pDC-FillRect(myrect2,&mybrush);CPen mypen;CPen*myoldPen;mypen.CreatePen(PS_SOLID,2,RGB(255,255,255); myoldPen=pDC-SelectObject(&mypen);/画黑框的白线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-SelectObject(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(int jj=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 Dc; 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.weitu=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);Dc.SelectObject(m_anniu3);pDC-BitBlt(180,10,160,160,&Dc,0,0,SRCCOPY);/显示黑框里的数字int nOldDC=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);CString str; /利用判断显示位数,不够三位前面加0if(leftnumTextOut(25,10,str);if(second10)str.Format(00%d,second);else if(secondTextOut(330,10,str);pDC-RestoreDC(nOldDC); 运行一下,外观已经出来了,只是还不能玩。那我们就来添加一些功能函数,使它可以玩。当然,如果你对程序已经有一定的经验的话,你就会指出上面的函数太长了。这并不太符合我们编程的要求。我们编程有一个讲究,就是尽量使函数的代码少,一般为一页左右,便于查看。那么,我们可以把上面的函数细分为几个小函数,然后在这个函数里面分别调用。按下鼠标左键:用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(Cant 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(leiab.shumu=-1)jieshu=1; /结束时,释放Timer KillTimer(1);/重画,因为这次重画将显示全部的雷,/不能用部分重画Invalidate(); else leiab.weitu=1;CRect rect;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);如果你现在运行的话,你会发现按下按钮时并不还原,这就涉及到鼠标函数:OnLButtonUp(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 CDC *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&point.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)le
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 毕业论文指导老师评语及答辩教师评语集锦
- 0822一级学科轻工技术与工程082203发酵工程专业硕士研究生培养方案
- 基于分时电价的热泵供热系统相变储热应用研究
- 硕士论文开题报告的内容和要求-开题报告
- 小米公司管理制度大全
- 临床试验设计在神经退行性疾病药物研发中的关键问题
- 毕业论文任务书的要求怎么写
- MBA论文模板及说明
- 延安大学西安创新学院学士学位授予细则(修订稿)
- 论文正文格式及字体要求
- 一级裁判笔试题库及答案
- 2025年国家开放大学(电大)《机械设计制造及其自动化》期末考试复习试题及答案解析
- 燃气管网自动化控制系统建设方案
- 安全文明施工及保证措施方案
- 新版西师版三年级上册数学全册教案教学设计含教学反思
- 特殊工序标准化作业指导书(SOS)
- 人工智能+智能金融区块链技术应用研究报告
- 屈光知识培训班课件
- 养老机构安全培训方案
- 2025年及未来5年中国橄榄油市场运行态势及行业发展前景预测报告
- 四季皮肤的特点及保养方案
评论
0/150
提交评论