毕业设计(论文)基于C++的扫雷游戏设计与实现

上传人:仙*** 文档编号:33889148 上传时间:2021-10-19 格式:DOC 页数:29 大小:179.01KB
返回 下载 相关 举报
毕业设计(论文)基于C++的扫雷游戏设计与实现_第1页
第1页 / 共29页
毕业设计(论文)基于C++的扫雷游戏设计与实现_第2页
第2页 / 共29页
毕业设计(论文)基于C++的扫雷游戏设计与实现_第3页
第3页 / 共29页
点击查看更多>>
资源描述
淮阴工学院毕业设计说明书(论文) 第 29 页 共 29 页1 引言扫雷最原始的版本可以追溯到1973年一款名为“方块”的游戏。不久之后,“方块”被改写成了游戏“Rlogic”。在“Rlogic”里,玩家的任务是作为美国海军陆战队队员,为指挥中心探出一条没有地雷的安全路线,如果路全被地雷堵死就算输。两年后,汤姆安德森在“Rlogic”的基础上又编写出了游戏“地雷”,由此奠定了现代扫雷游戏的雏形。1981年, 微软公司的罗伯特杜尔和卡特约翰逊两位工程师在Windows 3.1系统上加载了该游戏,扫雷游戏才正式在全世界推广开来。11 开发背景在计算机逐步渗入社会生活各个层面的今天,计算机已经成为了人们日常生活中的一部分,越来越多的人使用计算机办公、娱乐等等。扫雷游戏是Windows操作系统自带的一款小游戏,在过去的几年里,Windows操作系统历经数次换代更新,变得越来越庞大、复杂,功能也越来越强大,但是这款小游戏依然保持原来的容貌,可见这款小游戏受到越来越多人的喜爱。本次的毕业设计我将利用Visual C+作为开发工具,开发一款类似的“扫雷游戏”。12 开发的目的以及意义经过四年的大学学习,我对理论知识已经有了一定的了解与认知,本次的毕业设计便是将书本上所学的理论知识与实际相结合,同时也是对所学知识的一种检查,希望通过本次的毕业设计使自己在程序的开发和设计上有新的认识并能有所提高。本次毕业设计既锻炼了我们的实际动手能力,又在老师的指导下进行了一次模拟实际产品的开发,对于我们以后工作能力的培养具有重要意义。2 需求分析21 功能概述扫雷游戏的游戏界面如图1所示。在这个界面中,由众多面积均等的小方块所组成的区域称之为雷区,雷区的大小由用户设置的游戏等级决定。图 1 初级雷区游戏开始时,系统会在雷区的某些小方块中随机布下若干个地雷。安放好地雷的小方块称之为雷方块,其他的称之为非雷方块。部署完毕后,系统会在其他非雷方块中填充一些数字。某一个具体数字表示与其紧邻的8个方块中有多少雷方块。玩家可以根据这些信息去判断是否可以打开某些方块,并把认为是地雷的方块打上标识。如果某个数字方块周围的地雷全都标记完,可以指向该方块并同时点击鼠标左右键,将其周围剩下的方块挖开。如果编号方块周围地雷没有全部标记,在同时点击鼠标左右键时,其他隐藏或未标记的方块将被按下一次(即闪烁一下)。当玩家将所有地雷找出后,其余的非雷方块区域都已打开,此时游戏结束。在游戏过程中,一旦错误地打开了雷方块则立即失败,游戏结束;当玩家标识的地雷数超过程序设定,虽然打开了全部其余方块,游戏仍然不会结束。在游戏开始后,雷区上方有两个计数器。右边的计数器显示用户扫雷所花费的总时间,以秒为单位;左边的计数器显示当前还剩余多少个雷方块。2.2 功能需求分析游戏需要提供一个菜单栏,上面有不同的相关选项,如游戏的开始、难度设置、退出等。按功能将游戏区域分成两个区域:雷区和提示区。提示区包括两个计数器和一个按键操作结果图像提示。游戏过程中,当玩家用鼠标点击相应的方块,程序就会作出相应的鼠标响应事件,并伴随着GDI绘图,而众多鼠标事件的处理,都是围绕着实现扫雷程序的算法而衍生的。3 总体设计3.1 游戏框架的搭建(1) 工程项目的创建利用应用程序向导创建一个名称为Mine的工程项目。由于不需要诸如工具栏、状态栏等功能,并且扫雷游戏的框架是不允许改变窗口大小的,所以在向导的第四步里面把所有的选项置空,然后点击“Advanced”按钮,在弹出的对话框中选中“Windows Styles”选项卡,将“Maximize box”项置空,其他均使用默认设置。(2) 框架的改造通过类向导添加一个继承于CFrameWnd的类,命名为CMineWnd,删除CMineDoc、CMineView和CAboutDlg类,将CMineWnd类代替CFrameWnd,让程序启动的时候以此窗口为主窗口予以显示。结果如图2所示。图2 框架的改造3.2 菜单的制作参考Windows自带的扫雷游戏,创建出“游戏”和“帮助”菜单,然后通过菜单资源编辑器设定菜单的功能选项,包括难度级别的选择、颜色和音效是否开启、扫雷英雄榜、使用手册、关于软件的信息等。具体的菜单选项如图3所示。图3 游戏菜单(1) 难度级别的选择不同的难度级别有不同的雷区大小和不同的布雷数目,所以通过宏定义预定义不同级别的横向方块数目、纵向方块数目和雷数。并将该宏定义放入新建的头文件“MineDefs.h”中。窗口除了雷区外至少还包括蓝色窗口边缘Frame_wide、白色的视觉效果区line_wide、3D的外壳边框3D_line_wide、雷区mine_area_wide等。于是还需要定义关于位置的宏变量。由于难度级别的不同,窗口大小也会随之改变,因此通过在CMineWnd类增加一个改变窗口大小的函数SizeWindow()去实现。通过ClassWizard分别选择“初级”、“中级”和“高级”菜单资源ID,为它们添加处理函数OnMenuPrimary()、OnMenuSecond() 、OnMenuAdvance()。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) 雷区大小的自定义实现首先新建一个自定义雷区对话框资源(IDD_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 30) m_uWidth = 30;if (m_uHeight 24) m_uHeight = 24;if (m_uNumber m_uWidth * m_uHeight) m_uNumber = m_uWidth * m_uHeight - 1;CMineWnd *pMine = (CMineWnd*)AfxGetMainWnd();pMine-SetCustom(m_uWidth, m_uHeight, m_uNumber);/ TODO: Add extra validation hereCDialog:OnOK();(3) 使用帮助的实现由于Windows 自带有扫雷游戏,所以直接调用它的使用手。为“使用帮助”菜单选项创建命令消息处理函数OnMemuHelpUse(),代码如下所示。显示结果如图5所示。void CMineWnd:OnMemuHelpUse() ShellExecute(NULL,open,1.txt,NULL,NULL,SW_SHOW); 图5 使用帮助(4) 以往的记录每一次游戏破记录则将有关信息保存下来。显示结果如图6所示。图6 以往记录(5) 扫雷英雄榜的实现首先创建两个对话框模板,一个用作当用户胜利结束游戏并打破历史记录后弹出的签名记录对话框模板IDD_DLG_NEWRECORD,另外一个是用以显示以往最高的游戏记录的对话框模板IDD_DLG_HERO。如图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) 算法的设计把整个雷区看成一个二维数组,aij周围的雷个数是由如下8个雷区决定的(如果超出边界,应该再加以判断):ai-1j-1, ai-1j, ai-1j+1,ai, aij+1,ai+1 j-1, ai+1j, ai+1j+1,在被展开时,检查周围的雷数是否与周围标示出来的雷数相等,如果相等则展开周围未标示的雷区。这样新的雷区展开又触发这个事件,就这样递归下去,一直蔓延到不可展开的雷区。(2) 核心算法的实现整个游戏程序包含3个阶段:布雷、扫雷过程和结果(并不是操作结果展示,而是在扫雷过程中,玩家通过与游戏交互后的操作结果展示)。首先定义雷方块的数据结构,具体描述如下所示。typedef struct UINT uRow; /所在雷区二维数组的行UINT uCol; /所在雷区二位数组的列UINT uState; /当前状态UINT uAttrib; /方块属性UINT uOldState; /历史状态 MINEWND;/ 雷方块结构体然后定义雷方块的状态类别和属性类别。A 布雷随即获取一个状态为非雷的点,将它的属性标志为雷,重复这样的工作,直到布下足够的雷为止,其流程如图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; index uRow, m_pOldMine-uCol);if (m_uGameState = GS_WAIT)m_uBtnState = BUTTON_NORMAL;Invalidate();ReleaseCapture();return;/假若周围已经标识的雷周围真正的雷数,拓展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;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)LockResource(m_pSndClock), SND_MEMORY | SND_ASYNC | SND_NODEFAULT);/启动定时器m_uTimer = SetTimer(ID_TIMER_EVENT, 1000, NULL);/布雷LayMines(m_pOldMine-uRow, m_pOldMine-uCol);/改变游戏状态为运行/GS_RUNm_uGameState = GS_RUN;if (m_pOldMine-uOldState = STATE_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-uCol);/ 如果为空白区域,拓展,否则打开该区域(显示周围有多少雷数)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;/判断是否为胜利if (Victory()Invalidate();ReleaseCapture();return;break;case GS_VICTORY:case GS_DEAD:ReleaseCapture();return;default :break;m_uBtnState = BUTTON_NORMAL;Invalidate();else /点击非雷区域if (m_uGameState = GS_WAIT | m_uGameState = GS_RUN)m_uBtnState = BUTTON_NORMAL;InvalidateRect(rcBtn);ReleaseCapture();CWnd:OnLButtonUp(nFlags, point);在函数体的开始部分,先用rcBtn和rcMineArea两个矩形变量存储游戏的用户提示区域位置中的笑脸图区域以及雷区域的位置。利用接口函数PtInRect()判断当前鼠标的位置(由参数point携带鼠标当前位置信息)是否在这两个区域内,如果检测到鼠标左键点击并释放在笑脸图的按钮区域rcBtn上,则调用初始化函数重新开始游戏,如果检测到鼠标左键点击并释放在雷区域rcMineArea,假若当前游戏状态处于已初始化完成但尚未开始的状态GS_WAIT时,则打开计时器,并且调用LayMines()函数进行布雷,然后修改游戏状态为GS_RUN进入游戏。接着判断点击在小方块的状态是否被用于通过右键标记(可以标记为雷或者未知,此时游戏规则规定左键点击不生效),如果未标记,该状态为普通状态STATE_NORMAL时,先通过IsMine()检测是否点中地雷而失败地结束游戏,如果是,则调用函数Dead()来进行失败后的工作处理,反之对它进行打开显示与拓展操作。先通过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 = (col = 0) ? 0 : col - 1;UINT maxCol = col + 2;UINT around = GetAroundNum(row, col);/显示该区域的方块状态m_pMinesrowcol.uState = 15 - around;m_pMinesrowcol.uOldState = 15 - around;/ “打开”该区域,重绘DrawSpecialMine(row, col);/对周围一个雷都没有的空白区域if (around = 0)for (i = minRow; i maxRow; i+) for (j = minCol; j uRow, m_pNewMine-uCol);elseswitch(m_pNewMine-uState) /普通状态case STATE_NORMAL: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: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、ID_NUM_COLOR,并分别添加三个位图类型的变量,然后调用LoadBitmap(UINT nIDResource)函数来实现位图资源与变量的关联并添加函数DrawButton()、DrawMineArea()、DrawNumber()分别实现笑脸按钮、雷区、数字图像(计时器数字和剩余雷数数字)的绘图。绘制雷区的函数DrawMineArea()的实现代码如下。绘制笑脸按钮的函数实现类似。void CMineWnd:DrawMineArea(CPaintDC &dc)CDC dcMemory; /用作内存设备 /源设备dcMemory.CreateCompatibleDC(&dc); /使得这个设备与dc兼容 /dc是目标设备dcMemory.SelectObject(m_bmpMine); /将内存设备与位图资源关联for (UINT i = 0; im_uYNum; i+) for (UINT j = 0; jm_uXNum; j+) /根据ij区域的雷方块状态拷贝相应的图像到ij雷区的特定区域dc.StretchBlt(MINEAREA_FRAME_X+16*j, MINEAREA_FRAME_Y+16*i, 16, 16, &dcMemory, 0, 16*m_pMinesij.uState, 16, 16, SRCCOPY);(2)3D效果外壳模块的绘制首先调用FillSolidRect()在框架的左部和顶部分别绘制2个小白条,这样看起来有点立体的,然后调用Draw3dRect()在笑脸以及计时显示区域周围绘上一个较小的3D边框,最后在雷区周围绘上一个较大的3D边框。3D效果外壳绘制结果显示如图16。(3) 数字模块的绘制数字图像的绘制不是由鼠标事件触发的,而是由系统时间触发的。首先在CMineWnd类中添加定时器标识的成员变量m_uTimer和一个记录游戏开始直到目前所花费的时间的成员变量m_uSpendTime。接着在游戏的开始函数布下时间种子,时间间隔为1000us,然后选择到预定时间间隔后发送Windows命令消息函数WM_TIMER。接着在CMineWnd类中找到对应的消息WM_TIMER,并为其添加重写函数OnTimer(),该函数首先判断这次的WM_TIMER命令是否为所布下的时间种子到时而产生的,如果是则让使用的时间变量m_uSpendTime自增,然后通知系统重绘图像。雷区、笑脸按钮、3D效果外壳和数字图像的绘制都是在OnPaint()函数中实现的。其函数代码如下所示。void CMineWnd:OnPaint() CPaintDC dc(this); /创建一个CPaintDC类型的用以屏幕显示的dc设备 /参数是指向当前框架窗口CDC dcMemory;/ 内存设备CBitmap bitmap;/创建临时的位图资源if (!dc.IsPrinting() /判断不是使用打印机来进行绘制工作/ 使内存设备与dc设备兼容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&) 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, SRCCOPY);bitmap.DeleteObject();4 异常处理绘图过程大多放在OnDraw()或OnPaint()函数中,OnDraw()在进行屏幕显示时是由OnPaint()进行调用的。当窗口因为某种原因需要重绘时,总是先用背景色将显示区清除,然后才调用OnPaint(),而背景色往往与绘图内容反差很大,这样在短时间内背景色和显示图形的交替出现,使得显示窗口看起来会闪。对此可以使用内存设备环境来解决。用户可以把要显示的图形先在内存中绘制好,然后再一次性的将内存中的图形一个点一个点的覆盖到屏幕上去。在内存中绘图时,内存中的图像数据只作标识而没有显示效果。当贴到屏幕上时,由于内存中最终的图形与屏幕上显示图形差别很小,所以看起来就不会闪了。 结 论毕业设计是本科学习阶段一次非常难得的理论与实际相结合的机会,通过这次比较完整的一个游戏的开发,我摆脱了单纯的理论学习状态,和实际设计的结合锻炼了我的综合运用所学的专业基础知识,解决问题的能力,同时也提高我查阅文献资料、对程序整体的把握等其他能力与水平,而且通过对整体的掌控,对局部的取舍,以及对细节的斟酌处理,都使我的能力得到了锻炼,经验得到了丰富。这些都我们都希望通过毕业设计所能达到的目标。在毕业设计过程中,在导师王老师的带领下,不断地对源程序进行改进与完善,增加了一些以往扫雷游戏所没有的功能。并且在编写的过程中,各种组件的运用,各种算法的应用,各种控件的利用我都是随着毕业设计的不断深入而不断熟悉并逐步掌握的。和老师以及同学们的沟通交流跟使我对程序整体的规划与设计有了新的认识也对自己提出了新的要求。提高是有限的但也是全面的,正是这次设计让我积累了许多实际经验,也必然会让我在未来的工作学习中表现出更高的应变能力和理解能力。顺利如期的完成本次毕业设计给了我很大的信心,但是也让我看到了自己许多的不足,学习其实就是一个不断完善的过程,正视自己的不足之处,在以后的工作和学习中不断的弥补这些不足之处,在以后的工作中也要保持同样的态度,不断完善自己。致 谢经过几个月的不懈努力,我的毕业设计终于完成了。在这里,首先要感谢的就是我的指导老师王留洋。在这次的毕业设计过程中,从酝酿、选题、撰写到定稿,我遇到了许许多多的问题,有许许多多的地方需要改善,王老师总是耐心的帮我分析,并凭借他多年的工作经验给我提供合理的解决方案,让我更好地完成扫雷游戏的编写。在此,要向我的指导老师王留洋老师表示最诚挚的敬意和最衷心的感谢。同时我也要感谢大学期间所有教导过我的老师们,是他们传授给我方方面面的知识,拓宽了我的知识面,培养了我的功底,对毕业设计的完成不无裨益。我还要感谢和自己生活在一起的同学们,并不是所有的问题都得麻烦王老师,在有些问题上同学给了我很大的帮助。另外还要感谢计算机工程学院所提供的优良的实验环境,让我很好的锻炼了自己的实践能力。最后我还要感谢班主任这四年来对我的关心和培养,对我的学习和成长有着极为积极的作用。还有感谢陪伴了我的同学们,他们不仅在毕业设计上,而且在生活上给了我很大的帮助,正是由于有了他们的鼓励和帮助,我才能在遇到困难的时候坚持下来,在此衷心的感谢他们。参 考 文 献1 吴乃玲.C+程序设计.北京:人民邮电出版社,20082 邝玲辉. 应用系统开发.北京:人民邮电出版社,20073 罗齐.物流系统功能与构建战略分析.上海 200433 2003年第10期4 夏邦贵,郭胜等.Sql Server数据库开发入门与范例解析.北京:机械工业出版社,20045 闪四清.数据库原理与应用教程.北京:清华大学出版社,20046 甘仞初. 信息系统开发.北京:经济科学出版社,20007 陈禹.信息系统分析与设计.北京:电子工业出版社,2005 8 黄梯云.管理信息系统.北京:高等教育出版社,19999 方美琪.软件开发工具.北京:经济科学出版社,200210. 王珊.数据组织与管理.北京:经济科学出版社,1996
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!