ImageVerifierCode 换一换
格式:DOC , 页数:26 ,大小:305KB ,
资源ID:6546649      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/6546649.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(用VC++设计与实现扫雷系统.doc)为本站上传会员【pc****0】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

用VC++设计与实现扫雷系统.doc

1、 用VC++实现扫雷游戏程序 学生姓名:尹一笑 指导老师:颜宏文 摘 要: 本课程设计实现类似于Windows操作系统自带的扫雷游戏。在课程设计中,系统开发平台为Windows XP,程序设计语言采用Visual C++,程序运行平台为Windows 2000/XP。在程序设计中,把整个雷区看成一个二维数组,把雷方块定义为具有所在雷区二维数组的行和列、当前状态、方块属性、历史状态的结构体,采用了MFC机制解决问题的方法。整个游戏程序包括了布雷、扫雷过程和结果三个阶段,在处理鼠标响应事件中伴随着GDI绘图。程序通过调试运行,实现了设计目标,能够同时满足扫雷游戏初学者和高手

2、的需要。 关键词:扫雷游戏程序设计 ;Visual C++ 6.0;GDI绘图 1 绪 论 1.1 扫雷游戏的起源 扫雷最原始的版本可以追溯到1973年一款名为“方块”的游戏。不久之后,“方块”被改写成了游戏“Rlogic”。在“Rlogic”里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆·安德森在“Rlogic”的基础上又编写出了游戏“地雷”,由此奠定了现代扫雷游戏的雏形。1981年, 微软公司的罗伯特·杜尔和卡特·约翰逊两位工程师在Windows 3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来

3、 1.2 Visual C++ Visual C++为用户提供了一个可视化、通用的应用程序集成开发环境——Visual Studio。Visual Studio包含了一个文本编辑器、资源编辑器、工程编译工具、一个增量连接器、源代码浏览器、集成调试工具以及一套联机文档(MSDN)。通过Visual Studio,开发人员可以完成项目工程的创建、程序的编辑、修改、运行和调试等各种操作。Visual Studio采用标准的多窗口用户界面,提供了大量实用工具以支持可视化编程的特性,包括项目工作区、AppWizard(应用程序向导)、ClassWizard(类向导)、WizardBar(向导工

4、具条)、Component Gallery(组件画廊)等。 1.3 GDI原理 GDI(Graphics Device Interface,图形设备接口)主要负责在显示屏幕和打印设备等方面输出图像信息,是一组通过C++类实现的应用程序编程接口。它可以使得开发人员在将信息输出于屏幕或打印机的时候无需考虑具体的目标输出设备的硬件特性,只需调用GDI库的一些方法进行操作即可,而具体的绘图工作则由特定的设备驱动程序来完成,从而使开发人员能轻松地在不同的硬件中做图像绘制输出。 2 需求分析 本课程设计实现类似于Windows操作系统自带的扫雷游戏。 2.1 功能概述 扫雷游戏的游戏界面

5、如图1所示。在这个界面中,由众多面积均等的小方块所组成的区域称之为雷区,雷区的大小由用户设置的游戏等级决定。 玩家标定未知 未知区 周围雷数提示 玩家标定 地雷 图1 游戏开始时,系统会在雷区的某些小方块中随机布下若干个地雷。安放好地雷的小方块称之为雷方块,其他的称之为非雷方块。部署完毕后,系统会在其他非雷方块中填充一些数字。某一个具体数字表示与其紧邻的8个方块中有多少雷方块。玩家可以根据这些信息去判断是否可以打开某些方块,并把认为是地雷的方块打上标识。如果某个数字方块周围的地雷全都标记完,可以指向该方块并同时点击鼠标左右键,将其周围剩下的方块挖开。如果编号方块周围地雷

6、没有全部标记,在同时点击鼠标左右键时,其他隐藏或未标记的方块将被按下一次(即闪烁一下)。当玩家将所有地雷找出后,其余的非雷方块区域都已打开,此时游戏结束。在游戏过程中,一旦错误地打开了雷方块则立即失败,游戏结束;当玩家标识的地雷数超过程序设定,虽然打开了全部其余方块,游戏仍然不会结束。 在游戏开始后,雷区上方有两个计数器。右边的计数器显示用户扫雷所花费的总时间,以秒为单位;左边的计数器显示当前还剩余多少个雷方块。 2.2 功能需求分析 游戏需要提供一个菜单栏,上面有不同的相关选项,如游戏的开始、难度设置、退出等。按功能将游戏区域分成两个区域:雷区和提示区。提示区包括两个计数器和一个按键操

7、作结果图像提示。游戏过程中,当玩家用鼠标点击相应的方块,程序就会作出相应的鼠标响应事件,并伴随着GDI绘图,而众多鼠标事件的处理,都是围绕着实现扫雷程序的算法而衍生的。 3 总体设计 3.1 游戏框架的搭建 (1) 工程项目的创建 利用应用程序向导创建一个名称为Mine的工程项目。由于不需要诸如工具栏、状态栏等功能,并且扫雷游戏的框架是不允许改变窗口大小的,所以在向导的第四步里面把所有的选项置空,然后点击“Advanced”按钮,在弹出的对话框中选中“Windows Styles”选项卡,将“Maximize box”项置空,其他均使用默认设置。 (2) 框架的改造 通过类向

8、导添加一个继承于CFrameWnd的类,命名为CMineWnd,删除CMineDoc、CMineView和CAboutDlg类,将CMineWnd类代替CFrameWnd,让程序启动的时候以此窗口为主窗口予以显示。结果如图2所示。 图2 3.2 菜单的制作 参考Windows自带的扫雷游戏,创建出“游戏”和“帮助”菜单,然后通过菜单资源编辑器设定菜单的功能选项,包括难度级别的选择、颜色和音效是否开启、扫雷英雄榜、使用手册、关于软件的信息等。具体的菜单选项如图3所示。 图3 (1) 难度级别的选择 不同的难度级别有不同的雷区大小和不同的布雷数目,所以通过宏定义预定义不

9、同级别的横向方块数目、纵向方块数目和雷数。并将该宏定义放入新建的头文件“MineDefs.h”中。 窗口除了雷区外至少还包括蓝色窗口边缘Frame_wide、白色的视觉效果区line_wide、3D的外壳边框3D_line_wide、雷区mine_area_wide等。于是还需要定义关于位置的宏变量。 由于难度级别的不同,窗口大小也会随之改变,因此通过在CMineWnd类增加一个改变窗口大小的函数SizeWindow()去实现。 通过ClassWizard分别选择“初级”、“中级”和“高级”菜单资源ID,为它们添加处理函数OnMenuPrimary()、OnMenuSecond() 、O

10、nMenuAdvance()。OnMenuAdvance()的实现如下,另外两个类似。 void CMineWnd::OnMenuAdvance() { m_uLevel = LEVEL_ADVANCE; m_uXNum = ADVANCE_XNUM; m_uYNum = ADVANCE_YNUM; m_uMineNum = ADVANCE_MINENUM; SetCheckedLevel(); InitGame(); Invalidate(); SizeWindow(); } (2) 雷区大小的自定义实现 首先新建一个自定义雷区对话框资源(I

11、DD_DLG_CUSTOM),然后添加高度、宽度、雷数三个静态文本控件和三个对应的(IDC_HEIGHT)、(IDC_WIDTH) 、(IDC_NUMBER)编辑框控件,最后将OK和Cancel按钮分别改名为“确定”和“取消”。结果如图4。 图4 接着为该对话框创建CDlgCustom类,然后为三个编辑控件分别添加关联变量m_uHeight、m_uNumber、m_uWidth,最后为OK按钮创建命令消息处理函数OnOK(),代码如下所示。 void CDlgCustom::OnOK() { UpdateData(); if (m_uWidth < 9) m_uWidth

12、 = 9; if (m_uWidth > 30) m_uWidth = 30; if (m_uHeight < 9) m_uHeight = 9; if (m_uHeight > 24) m_uHeight = 24; if (m_uNumber < 10) m_uNumber = 10; if (m_uNumber > m_uWidth * m_uHeight) m_uNumber = m_uWidth * m_uHeight - 1; CMineWnd *pMine = (CMineWnd*)AfxGetMainWnd(); pMine->SetCustom(m

13、uWidth, m_uHeight, m_uNumber);// TODO: Add extra validation here CDialog::OnOK(); } (3) 使用帮助的实现 由于Windows 自带有扫雷游戏,所以直接调用它的使用手。为“使用帮助”菜单选项创建命令消息处理函数OnMemuHelpUse(),代码如下所示。显示结果如图5所示。 void CMineWnd::OnMemuHelpUse() { //在命令行调用HH.exe,并输入参数NTHelp.CHM, //令其打开该文件,即Windows 自带有扫雷游戏的是使用手册 ::Wi

14、nExec("HH NTHelp.CHM", SW_SHOW); } 图5 (4) 关于信息的实现 关于信息的实现代码如下所示。显示结果如图6所示。 void CMineWnd::OnMemuAbout() { ShellAbout(this->m_hWnd, "扫雷", "yixiaoqianjin@",NULL); } 图6 (5) 扫雷英雄榜的实现 首先创建两个对话框模板,一个用作当用户胜利结束游戏并打破历史记录后弹出的签名记录对话框模板IDD_DLG_NEWRECORD,另外一个是用以显示以往最高的游戏记录的对话框模板IDD_DLG_HERO。如

15、图7和图8所示。 图7 图8 然后为IDD_DLG_HERO对话框模板创建CDlgHero类,分别为编辑框控件添加关联变量m_szBHolder、m_szBRecord、m_szEHolder、m_szERecord、m_szIHolder、m_szIRecord,并将Cancel按钮的ID和标题分别改为IDC_RESET和重新计分,三个静态文本标题设置为初级记录、中级记录、高级记录,最后为重新计分按钮创建命令消息处理函数OnReset()和其他成员函数。对IDD_DLG_NEWRECORD对话框模板类似处理。 3.3布雷,扫雷核心算法的设计与实现 (1) 算法的设计 把整

16、个雷区看成一个二维数组,a[i][j]周围的雷个数是由如下8个雷区决定的(如果超出边界,应该再加以判断): a[i-1][j-1], a[i-1][j], a[i-1][j+1], a[i][], a[i][j+1], a[i+1][ j-1], a[i+1][j], a[i+1][j+1], 在被展开时,检查周围的雷数是否与周围标示出来的雷数相等,如果相等则展开周围未标示的雷区。这样新的雷区展开又触发这个事件,就这样递归下去,一直蔓延到不可展开的雷区。 (2) 核心算法的实现 整个游戏程序包含3个阶段:布雷、扫雷过程和结果(并不是操作结

17、果展示,而是在扫雷过程中,玩家通过与游戏交互后的操作结果展示)。 首先定义雷方块的数据结构,具体描述如下所示。 typedef struct { UINT uRow; //所在雷区二维数组的行 UINT uCol; //所在雷区二位数组的列 UINT uState; //当前状态 UINT uAttrib; //方块属性 UINT uOldState; //历史状态 } MINEWND; // 雷方块结构体 然后定义雷方块的状态类别和属性类别。 A 布雷 随即获取一个状态为非雷的点,将它

18、的属性标志为雷,重复这样的工作,直到布下足够的雷为止,其流程如图9所示。 开始 生成随机的雷方块的坐标(x,y) 判断(x,y)区域是否已经布下雷 在(x,y)区域布雷,修改状态数据 判断是否布下所有雷 结束 否 是 是 否 图9 在CMineWnd类中添加游戏的布雷模块的处理函数,该函数的实现如下。 void CMineWnd::LayMines(UINT row, UINT col) { //埋下随机种子 srand( (unsigned)time( NULL ) ); UINT i, j; for(UINT index = 0; i

19、ndex < m_uMineNum;) { //取随即数 i = rand() % m_uYNum; j = rand() % m_uXNum; if (i == row && j == col) continue; if(m_pMines[i][j].uAttrib != ATTRIB_MINE) { m_pMines[i][j].uAttrib = ATTRIB_MINE;//修改属性为雷 index++; } } } B 扫雷 鼠标左击事件 其流程如图10所示。 开始 获取该区域周围雷 的

20、数目num Num = 0 拓展该区域 修改标志,打开显示该区域 结束 否 是 图11 开始 在雷区 雷方块定位 游戏结束 胜利 失败处理 显示 结束 继续处理 打开区域 拓展最大的可能 显示范围 其他区域处理 胜利处理 否 是 是 否 否 图10 当鼠标左键点击雷区域,并且该区域不是雷方块,需要进行打开以及拓展工作。流程如图11所示。 鼠标左键点击事件的关键代码如下所示。 void CMineWnd::OnLButtonUp(UINT nFlags, CPoint point) { //笑脸图按钮所在的区域

21、CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); //雷区所在的区域 CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); if (rcBtn.PtInRect(point)) {// 点击笑脸图 Invalidate(); InitGame(); } else if (rcMineAre

22、a.PtInRect(point)) {//点击雷区域 CString value; UINT around = 0; //根据不同的游戏状态作处理 switch(m_uGameState) { //游戏进行状态 case GS_WAIT: case GS_RUN: // first get the MINEWND which if pushing down m_pOldMine = GetMine(point.x, point.y); if (!m_pOldMine) { ReleaseCap

23、ture(); return; } //检测判断当前状态是否为左右鼠标同时按下 if (m_bLRBtnDown) { m_bLRBtnDown = FALSE; OnLRBtnUp(m_pOldMine->uRow, m_pOldMine->uCol); if (m_uGameState == GS_WAIT) { m_uBtnState = BUTTON_NORMAL; Invalidate(); ReleaseCapture(); return;

24、} //假若周围已经标识的雷=周围真正的雷数,拓展 if (m_pOldMine->uState != STATE_FLAG) { OpenAround(m_pOldMine->uRow, m_pOldMine->uCol); } if (ErrorAroundFlag(m_pOldMine->uRow, m_pOldMine->uCol)) { Dead(m_pOldMine->uRow, m_pOldMine->uCol); ReleaseCapture(); return;

25、 } } else { //如果游戏尚未开始,点击左键启动游戏 if (m_uGameState == GS_WAIT) { if (m_uTimer) { KillTimer(ID_TIMER_EVENT); m_uTimer = 0; } m_uSpendTime = 1; Invalidate(); if (m_bSoundful) { sndPlaySound((LPCTSTR)LockResourc

26、e(m_pSndClock), SND_MEMORY | SND_ASYNC | SND_NODEFAULT); } //启动定时器 m_uTimer = SetTimer(ID_TIMER_EVENT, 1000, NULL); //布雷 LayMines(m_pOldMine->uRow, m_pOldMine->uCol); //改变游戏状态为"运行/GS_RUN" m_uGameState = GS_RUN; } if (m_pOldMine->uOldState == STAT

27、E_NORMAL) {//当该雷区域为正常未作标记才打开 //如果该区域为雷,则死亡 if (IsMine(m_pOldMine->uRow, m_pOldMine->uCol)) { Dead(m_pOldMine->uRow, m_pOldMine->uCol); ReleaseCapture(); return; } //不是雷的时候,获取其周围的雷数目 around = GetAroundNum(m_pOldMine->uRow, m_pOldMine->uCo

28、l); // 如果为空白区域,拓展,否则打开该区域(显示周围有多少雷数) if (around == 0) ExpandMines(m_pOldMine->uRow, m_pOldMine->uCol); else DrawDownNum(m_pOldMine, around); } else if (m_pOldMine->uOldState == STATE_DICEY) { //标志为“?”问号的时候 m_pOldMine->uState = STATE_DICEY; } //判断是否为胜利

29、 if (Victory()) { Invalidate(); ReleaseCapture(); return; } } break; case GS_VICTORY: case GS_DEAD: ReleaseCapture(); return; default : break; } m_uBtnState = BUTTON_NORMAL; Invalidate(); } else {//点击非雷区域 if (m_uGameSta

30、te == GS_WAIT || m_uGameState == GS_RUN) { m_uBtnState = BUTTON_NORMAL; InvalidateRect(rcBtn); } } ReleaseCapture(); CWnd::OnLButtonUp(nFlags, point); } 在函数体的开始部分,先用rcBtn和rcMineArea两个矩形变量存储游戏的用户提示区域位置中的笑脸图区域以及雷区域的位置。利用接口函数PtInRect()判断当前鼠标的位置(由参数point携带鼠标当前位置信息)是否在这两个区域内,如果检

31、测到鼠标左键点击并释放在笑脸图的按钮区域rcBtn上,则调用初始化函数重新开始游戏,如果检测到鼠标左键点击并释放在雷区域rcMineArea,假若当前游戏状态处于已初始化完成但尚未开始的状态GS_WAIT时,则打开计时器,并且调用LayMines()函数进行布雷,然后修改游戏状态为GS_RUN进入游戏。接着判断点击在小方块的状态是否被用于通过右键标记(可以标记为雷或者未知,此时游戏规则规定左键点击不生效),如果未标记,该状态为普通状态STATE_NORMAL时,先通过IsMine()检测是否点中地雷而失败地结束游戏,如果是,则调用函数Dead()来进行失败后的工作处理,反之对它进行打开显示与拓

32、展操作。先通过GetAroundNum()函数获取当前小方块相邻的8个位置的雷数。如果当前小方块相邻区域的雷数为0,则可以向8个方向进行拓展,并显示该方块区域,直到不可拓展为止;如果当前小方块相邻区域的雷数不为0,则显示该方块区域的相邻雷数,用作提供用户对其他位置的信息判断的提示。拓展操作的实现代码如下。 void CMineWnd::ExpandMines(UINT row, UINT col) { UINT i, j; UINT minRow = (row == 0) ? 0 : row - 1; UINT maxRow = row + 2; UINT minCol =

33、 (col == 0) ? 0 : col - 1; UINT maxCol = col + 2; UINT around = GetAroundNum(row, col); //显示该区域的方块状态 m_pMines[row][col].uState = 15 - around; m_pMines[row][col].uOldState = 15 - around; // “打开”该区域,重绘 DrawSpecialMine(row, col); //对周围一个雷都没有的空白区域 if (around == 0) { for (i = minRo

34、w; i < maxRow; i++) { for (j = minCol; j < maxCol; j++) {//对于周围可以拓展的区域进行的规拓展 if (!(i == row && j == col) && m_pMines[i][j].uState == STATE_NORMAL && m_pMines[i][j].uAttrib != ATTRIB_MINE) { if (!IsInMineArea(i, j)) continue; ExpandMines(i, j); // 递

35、归拓展操作 } } } } } 经过打开或拓展后,最后通过Victory()判断游戏是否已经胜利结束,如果是则作胜利处理。 鼠标右击事件 其流程如图12所示。 开始 雷方块定位 判断历史属性以及相关状态 修改相关状态 显示 结束 图12 其实现代码如下所示。 void CMineWnd::OnRButtonDown(UINT nFlags, CPoint point) { //笑脸图按钮所在的区域 CRect rcBtn(m_uBtnRect[1], 15, m_uBtnRect[2], 39); //雷区所在的区域

36、 CRect rcMineArea(MINE_AREA_LEFT, MINE_AREA_TOP, MINE_AREA_LEFT + m_uXNum * MINE_WIDTH, MINE_AREA_TOP + m_uYNum * MINE_HEIGHT); m_bLRBtnDown = FALSE; if (rcMineArea.PtInRect(point)) {//点击雷区域 if (m_uGameState == GS_WAIT || m_uGameState == GS_RUN) { m_pNewMine = GetMine(po

37、int.x, point.y); if (!m_pNewMine) return; //检测判断当前状态是否为左右鼠标同时按下 if (nFlags == (MK_LBUTTON | MK_RBUTTON)) { m_bLRBtnDown = TRUE; OnLRBtnDown(m_pNewMine->uRow, m_pNewMine->uCol); } else { switch(m_pNewMine->uState) { //普通状态 case STATE_NORMAL:

38、 m_pNewMine->uState = STATE_FLAG; m_pNewMine->uOldState = STATE_FLAG; m_nLeaveNum--; break; //标记状态 case STATE_FLAG: m_pNewMine->uState = STATE_DICEY; m_pNewMine->uOldState = STATE_DICEY; m_nLeaveNum++; break; //未知状态 case STATE_DICEY:

39、 m_pNewMine->uState = STATE_NORMAL; m_pNewMine->uOldState = STATE_NORMAL; break; default: break; } } Invalidate(); } } CWnd::OnRButtonDown(nFlags, point); } 3.4 绘图界面的设计 (1)雷区、笑脸模块的绘制 添加三个位图资源如图13所示。 图13 ID分别为ID_BTN_COLOR、ID_MINE_COLOR

40、ID_NUM_COLOR,并分别添加三个位图类型的变量,然后调用LoadBitmap(UINT nIDResource)函数来实现位图资源与变量的关联并添加函数DrawButton()、DrawMineArea()、DrawNumber()分别实现笑脸按钮、雷区、数字图像(计时器数字和剩余雷数数字)的绘图。绘制雷区的函数DrawMineArea()的实现代码如下。绘制笑脸按钮的函数实现类似。 void CMineWnd::DrawMineArea(CPaintDC &dc) { CDC dcMemory; //用作内存设备 //源设备 dcMemory.CreateCompa

41、tibleDC(&dc); //使得这个设备与dc兼容 //dc是目标设备 dcMemory.SelectObject(m_bmpMine); //将内存设备与位图资源关联 for (UINT i = 0; i

42、0, 16*m_pMines[i][j].uState, 16, 16, SRCCOPY); } } } 雷区绘制结果显示如图14,笑脸按钮绘制结果显示如图15。 图14 图15 (2)3D效果外壳模块的绘制 首先调用FillSolidRect()在框架的左部和顶部分别绘制2个小白条,这样看起来有点立体的,然后调用Draw3dRect()在笑脸以及计时显示区域周围绘上一个较小的3D边框,最后在雷区周围绘上一个较大的3D边框。3D效果外壳绘制结果显示如图16。 图16 (3) 数字模块的

43、绘制 数字图像的绘制不是由鼠标事件触发的,而是由系统时间触发的。首先在CMineWnd类中添加定时器标识的成员变量m_uTimer和一个记录游戏开始直到目前所花费的时间的成员变量m_uSpendTime。接着在游戏的开始函数布下时间种子,时间间隔为1000us,然后选择到预定时间间隔后发送Windows命令消息函数WM_TIMER。接着在CMineWnd类中找到对应的消息WM_TIMER,并为其添加重写函数OnTimer(),该函数首先判断这次的WM_TIMER命令是否为所布下的时间种子到时而产生的,如果是则让使用的时间变量m_uSpendTime自增,然后通知系统重绘图像。数字图像的绘制显

44、示如图17。 图17 雷区、笑脸按钮、3D效果外壳和数字图像的绘制都是在OnPaint()函数中实现的。其函数代码如下所示。 void CMineWnd::OnPaint() { CPaintDC dc(this); //创建一个CPaintDC类型的用以屏幕显示的dc设备 //参数是指向当前框架窗口 CDC dcMemory; // 内存设备 CBitmap bitmap; //创建临时的位图资源 if (!dc.IsPrinting()) //判断不是使用打印机来进行绘制工作 { // 使内存设备与dc设备兼容

45、if (dcMemory.CreateCompatibleDC(&dc)) { // 使得bitmap与实际显示的dc设备兼容 if(bitmap.CreateCompatibleBitmap(&dc,m_rcClient.right, m_rcClient.bottom)) { // 内存设备选择物件-位图 dcMemory.SelectObject(&bitmap); //绘制背景框 dcMemory.FillRect(&m_rcClient, &m_brsBG); DrawButton((CPaintDC&

46、) dcMemory);//笑脸按钮绘图 DrawNumber((CPaintDC&) dcMemory);//数字图像绘图 DrawShell((CPaintDC&) dcMemory);//3D效果外壳绘图 DrawMineArea((CPaintDC&) dcMemory);//雷区绘图 // 将内存设备的内容拷贝到实际屏幕显示的设备 dc.BitBlt(m_rcClient.left, m_rcClient.top, m_rcClient.right, m_rcClient.bottom, &dcMemory, 0, 0, SRCC

47、OPY); bitmap.DeleteObject(); } } } } 5 异常处理 绘图过程大多放在OnDraw()或OnPaint()函数中,OnDraw()在进行屏幕显示时是由OnPaint()进行调用的。当窗口因为某种原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint(),而背景色往往与绘图内容反差很大,这样在短时间内背景色和显示图形的交替出现,使得显示窗口看起来会闪。对此可以使用内存设备环境来解决。用户可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形一个点一个点的覆盖到屏幕上去。在内存中绘图时,内存中的图像数据

48、只作标识而没有显示效果。当贴到屏幕上时,由于内存中最终的图形与屏幕上显示图形差别很小,所以看起来就不会闪了。 6 结束语 本次课程设计让我初步了解了电子游戏所涉及到的有关技术、方法,做到了能图、文、声并茂地演示扫雷游戏。在这次课程设计过程中,遇到了很多问题,利用图书馆和搜索引擎,我查阅了很多资料,同时颜宏文老师和尹存祥同学也给了我很多帮助,最终问题都得到了解决。我也学到了很多新知识,并且对以前的知识进行了回顾。通过不断上机实验,调试程序,总结经验,增强了动手实践能力和解决问题的能力。 7参考文献 [1]Ben Sawyer. 游戏软件设计与开发指南[M].北京:人民邮电出版社,

49、1998.8~46 [2]电脑商情报——游戏天地精华本[J]. 2003年合订本,2004年合订本 [3]程辉.青少年与网络游戏专题报道[EB/OL]. upload/c2005/200518341026/index.html ,2005 [4]游戏工作委员会. 国内游戏产业二十年发展概况[EB/OL].http://www.donews. com/Content/200506/d4df1e65005843c7bb987db5349811a7.shtm,2005 [5]本千寻.Visual C++角色扮演游戏程序设计[M].北京:中国铁道出版社,2004 [6]钦科技. Visual C++游戏设计[M]. 北京:科海电子出版社,2003.1~211 [7]杨正华等. Visual C++游戏编程导学[M].北京:清华大学出版社,2003.206~268 [8]肖永亮等. 计算机游戏程序设计[M]. 北京:电子工业出版社,2005 [9]Tom Meigs. 顶级游戏设计[M]. 北京:电子工业出版社,2004 [10]Richard Rouse III 游戏设计——原理与实践[M]. 北京:电子工业出版社,2003 [11

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服