基于MFC的拼图游戏设计宋富冉操梦雅摘要:拼图游戏是一个广受欢迎的智力游戏,按人数参与个数可分为单人游戏和多人游戏,按拼图规则它可分为摆放式和挪动式两种类型。
本设计是基于Visual C++ 6.0和MFC的拼图游戏设计,设计了一个操作简单的挪动式单人拼图游戏。
本游戏主要包括游戏界面设计、难易度选择、游戏图片选择、游戏系统设计、判断拼图是否成功等几个模块,程序设计中应用了类、数组、鼠标响应、菜单消息响应等元素和语句。
此游戏的设计主要以学习和熟悉Visual C++ 6.0和MFC软件开发为主要目的。
关键词:拼图; Visual C++ 6.0; MFC1.任务描述1.1 拼图简单介绍拼图游戏是广受欢迎的一种智力游戏,它的变化多端,难度不一,让人百玩不厌。
个性化的拼图,拼凑的不仅仅是一张照片,而是一个故事,一段回忆,一段温情。
每一片的单片都有属于它自己的位置,就像每段回忆都有属于它的故事,你要将它放在专属的地方。
你可以把你记忆中最深刻的片段,你挚爱的照片,你最难忘的一瞬间,做成拼图,在你想起的时候一一拼起。
拼图游戏不仅能增强思维能力,提高智力,而且富含哲理,有助于加强我们的动手能力和我们的洞察能力。
1.2 基本设计要求我们设计的拼图游戏是一个具有简单的系统界面,操作简单易行,上手快,适用于广大用户的小游戏。
此游戏分散的小图片的移动规则是小图片会朝着空位置方向移动,玩家在界面上先通过鼠标点击“游戏图片选择”选择要拼的图片,然后通过鼠标左键点击要移动的小图片,小图片会自动移动到原来没有图片的位置,移动时,预备移动的图片旁边必须要有可供移动的位置,直到拼合出原来的图片,并且成功拼成图片后会出现“看来这对你来说太简单了,挑战更高难度吧!”一句话。
具体设计要求如下:(1)可以打开并显示.bmp任意大小的图片;(2)游戏开始之后,可以自动随机打乱图片;(3)用户可以点击方块进行上下左右的交换,直到拼出原图片;(4)系统能够自动检测用户是否拼出原图,并提示用户拼图是否成功。
2.系统需求分析2.1 功能需求分析(1)用户能用鼠标控制系统界面上各个菜单选项的选择。
(2)游戏难度选择功能:用户可以通过参数设置自定义选择游戏的难度,系统开始默认的是9块,如果用户想挑战更困难的,可以在设置参数设置中进行相应的参数修改,比如4*4=16块、5*5=25块、3*4=12块等。
(3)游戏音乐播放功能:用户可以根据自己的喜好进行选择是否播放音乐,所播放的音乐也是用户根据喜好自己来选择的。
(4)游戏原图显示功能:当玩家在玩游戏过程中忘记各个小图片的整体排列位置时能够进入原图显示功能查看完整图片,参考原图进行拼图游戏,以提高游戏的趣味性。
(5)游戏判断功能:用户通过移动每一小块图片,最终拼出和导入的图片一致时,系统则会判断你拼图成功,并提示“看来这对你来说太简单了,挑战更高难度吧!”这句话。
图2-1 系统功能模块2.2 界面设计需求该拼图游戏是以对话框的形式显示出来,顶部为标题栏,接着是菜单栏,菜单栏上是五个菜单选项:主菜单、游戏图像选择、参数设置、原图设置、帮助。
然后接下来就是拼图游戏的拼图部分主界面。
2.3 系统其他需求分析(1)性能要求可靠性强、实时性好(2)设计约束开发工具:VC++ 6.0、运行环境:windows 2000以上(3)软硬件要求在windows平台上运行、应用程序用C++语言开发、客户端使用普通个人计算机。
2.4系统流程图图2-2系统流程图流程图说明:(1)启动程序,进入游戏界面。
(2)用户根据自己的想法和意愿选择游戏图片,并进行游戏参数设置后,程序有相应的操作,对应程序根据参数设置进行图片的分割,游戏区域均分,将分割后的子图片填充到游戏区域相等面积的方格内,并记录初始各个子图片的原始坐标,然后随机走动200步。
(这个过程执行只在一瞬间即可完成)显示出游戏界面。
(3)用户开始游戏,使用鼠标或者键盘上下左右键来进行拼图,在此过程中,程序会实时刷新画面,并全盘对比各个子图片的坐标和原始坐标是否相同,若相同则游戏结束,系统提示拼图成功,若不同,则用户继续游戏,继续移动子图片,判断程序循环执行,直到拼图成功。
(4)若在游戏过程当中,想要参照原图,则点击原图显示菜单选项,原图像显示子程序被调用,并将原图像显示在游戏区域一侧,供游戏者参考,不想参考可再次点击原图显示不显示原图像。
(5)参数设置选项,可以进行拼图的难度设置,即图块的行列数设置,以及游戏背景音乐的设置,在此过程中程序将执行相应的子函数进行响应用户操作。
(6)中途可以随时重新开始新游戏,退出游戏,参数设置,原图显示与否,调换游戏图片等,不必关闭程序重新打开。
并且确保每次拼图必定会成功,不会出现拼图不成功的情况。
3.函数功能设置(1)int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { //切换"文本提示形式"菜单选项为"图像提示形式"HMENU hmenu;hmenu=::GetMenu(m_hWnd); //获取主菜单控制权//获取图片选取菜单选项所在的子菜单栏目的控制权hmenu=::GetSubMenu(hmenu,1);char * hbmp;UINT ITEM_ID;HINSTANCE hinst = AfxGetInstanceHandle();//获取实例的句柄//载入相关的缩小预览型的位图图片,并进行相关选项的属性修改hbmp=(char *)LoadBitmap(hinst,MAKEINTRESOURCE(IDB_PIC1));//图片的载入ITEM_ID = ::GetMenuItemID(hmenu,1); //相应菜单选项的ID获取//属性修改--切换成图像显示方式::ModifyMenu(hmenu,1,MF_BYPOSITION|MF_BITMAP,ITEM_ID,hbmp);}(2)BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT,CCreateContext* pContext){ //创建1行2列的分裂视图,设定出游戏界面(参见图3-1)m_wndSplitter.CreateStatic(this,1, 2);m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CSFRCMYPINTUView), CSize(300,0), pContext);m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(COrgView), CSize(0,0),pContext);m_wndSplitter.SetActivePane(0,0); //将第一个作为当前激活状态的视图}图3-1 游戏初始界面(3)BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { //设置对应图3-1的初始界面窗口显示的大小cs.cx = 600;cs.cy = 400;cs.style = WS_OVERLAPPED | WS_CAPTION | FWS_ADDTOTITLE | WS_THICKFRAME | WS_SYSMENU;cs.dwExStyle = WS_EX_ACCEPTFILES;}(4)void COrgView::OnDraw(CDC* pDC){// 源图像绘制函数CSFRCMYPINTUDoc* pDoc = (CSFRCMYPINTUDoc*)GetDocument()CDC memdc; //使用内存DCmemdc.CreateCompatibleDC(pDC);memdc.SelectObject(pDoc->m_bitmap);pDC->BitBlt(0,0,pDoc->m_bmpWidth,pDoc->m_bmpHeight,&memdc,0,0,SRCCOPY); / /整幅图拷贝}void COrgView::DrawAll(CDC *pDC){//是否显示原图像的响应函数}(5) void COrgView::OnUpdate(CView* pSender, LPARAM lHint, CObject*pHint){//更新界面函数}(6)void CSetitingDlg::OK(){//确定并保存参设设置的所有更改(参见图3-2)}(7)BOOL CSetitingDlg::OnInitDialog(){CDialog::OnInitDialog();//初始化各个游戏参数(部分可参见图3-2)m_iCols=AfxGetApp()->GetProfileInt(_T("游戏参数"),_T("hnums"),3);m_iRows=AfxGetApp()->GetProfileInt(_T("游戏参数"),_T("vnums"),3);} (8)void CSetitingDlg::OnOpen(){//选取播放背景音乐时,打开相关文件函数(参见图3-2)CString strFilter="MP3文件(*.mp3)|*.mp3";CFileDialog fileopen(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFNOVERWRITEPROMPT,strFilter);if(fileopen.DoModal()==IDOK)m_strMusicFileName=fileopen.GetPathName();UpdateData(FALSE);} (9)void CSFRCMYPINTUDoc::GameMixMove(){// 游戏初始化,随机打乱图像,随机走300步}(10)void CSFRCMYPINTUDoc::GameMove(UINT nChar){//根据按键输入指示命令作移动操作函数,与(9)协作}(11)BOOL CSFRCMYPINTUDoc::IsWin(void){//检测是否拼图成功函数//胜利的检测方法是判断地图的所有方块的内部数据是否全为其行列数,是则表示排列好,胜利}(12)void CSFRCMYPINTUDoc::MapInitial(){//图片数据的初始化函数int i,j;//将原来各个位置的数据填好其所在的行ID,列IDfor(i=1;i<=hnums;i++){for(j=1;j<=vnums;j++){m_map[i][j].row =i; m_map[i][j].col =j;}}} (13)void CSFRCMYPINTUDoc::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags){ // 处理键盘事件函数}(14)void CSFRCMYPINTUDoc::OnMenuOrgPicShow(){// 修改窗口是否显示源图的菜单消息处理函数m_bShowOrgPic = !m_bShowOrgPic; //修改原来的显示SetWindow_N_ViewSize(); //重设窗口大小与视图分布}(15)void CSFRCMYPINTUDoc::OnNewGame(){//开始新游戏函数(参见图3-1)SetWindow_N_ViewSize();MapInitial(); //地图的初始化m_blankPos.row =hnums; //打乱前将空白块起点放在右下角m_blankPos.col =vnums;GameMixMove();// 打乱地图(随机移动200步)UpdateAllViews(NULL); //更新视图}(16)void CSFRCMYPINTUDoc::OnPic1(){//游戏图片选取函数(参见图3-1)PicSelect(IDB_BITMAP1);}(17)void CSFRCMYPINTUDoc::OnSet(){//游戏参数设置响应函数(参见图3-2)}图3-2 参数设置对话框界面(18)void CSFRCMYPINTUDoc::OnUserpic(){// 用户选择路径自定义图片函数}(19)void CSFRCMYPINTUDoc::SetWindow_N_ViewSize(){//设置开始游戏后游戏窗口界面大小函数}(20)void CSFRCMYPINTUView::OnLButtonDown(UINT nFlags, CPoint point) {// 处理鼠标左键消息函数CSFRCMYPINTUDoc* pDoc = (CSFRCMYPINTUDoc*)GetDocument();pos DownPos; //计算出鼠标点击所在的cell方块位置DownPos.row =point.x/pDoc->m_cellWidth+1;DownPos.col =point.y/pDoc->m_cellHeight+1;//根据当前空白方块位置将鼠标点击其相邻方块的情况if(abs(DownPos.row-pDoc->m_blankPos.row)+abs(DownPos.col-pDoc->m_b lankPos.col)==1){if(DownPos.row - pDoc->m_blankPos.row == 1){pDoc->OnKeyDown(VK_RIGHT,0,0);}………………(中间略去)………………………….CView::OnLButtonDown(nFlags, point);}(21)void CSFRCMYPINTUView::DrawGameBlocks(CDC *pDC){// 绘制游戏所有当前散乱的方块}(22)void CSFRCMYPINTUView::DrawCellBlock(CDC *pDC, pos destPos, pos srcPos){ //根据源方块的位置和目标放开位置(当前方块实际位置)} (23)void CSFRCMYPINTUDoc::PlayMusic(){ // 播放背景音乐函数//说明:利用MCI机制控制媒体设备放音}4.数据结构的设计在函数功能的设计中我们提到了相关的结构体的定义,在这里给出重要的结构框架定义:(1 ) struct pos //方块位置结构{int row; //图像所在的行坐标int col; //图像所在的列坐标};(2) class OrgView:public CView //原图像显示类{void COrgView::DrawAll(CDC *pDC){}void COrgView::OnDraw(CDC* pDC){}…….};(3) class CSetitingDlg : public CDialog //参数和音乐播放等对话框对应设置处理类{void CSetitingDlg::OK(){}void CSetitingDlg::OnOpen(){}BOOL CSetitingDlg::OnInitDialog(){}…….};(4) class CSFRCMYPINTUApp : public CWinApp //程序基础类{……};(5) class CSFRCMYPINTUDoc : public CDocument //程序基础文档类{BOOL CSFRCMYPINTUDoc::IsWin(void){}void CSFRCMYPINTUDoc::OnKeyDown(UINT nChar, UINTnRepCnt, UINT nFlags){}void CSFRCMYPINTUDoc::OnNewGame() {}void CSFRCMYPINTUDoc::OnPic1() {}void CSFRCMYPINTUDoc::OnSet(){}void CSFRCMYPINTUDoc::OnUserpic() {}void CSFRCMYPINTUDoc::PlayMusic(){}…….};(6) class CSFRCMYPINTUView : public CView//程序基础视图类{void CSFRCMYPINTUView::DrawLines(CDC *pDC){}void CSFRCMYPINTUView::DrawBlankBlock(CDC *pDC){}void CSFRCMYPINTUView::DrawCellBlock(CDC *pDC, posdestPos, pos srcPos){}void CSFRCMYPINTUView::OnLButtonDown(UINT nFlags,CPoint point){}void CSFRCMYPINTUView::OnDraw(CDC* pDC){}……};(7) class CAboutDlg : public CDialog//程序基础对话框类{…….};(8) class CMainFrame : public CFrameWnd//程序主函数类{int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){}BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){}……};5.详细设计5.1 初始窗体设计利用MFC AppWinzard生成五子棋游戏应用程序框架具体步骤如下:1.执行VC程序,选择File|New命令,弹出New对话框.单击Projects标签,转到Projects选项卡,选择MFC AppWizard(exe)选项,然后在Project name 文本框中输入SFRCMYPINTU。