1、MFC综合练习 开发自己的推箱子应用程序MFC综合练习 开发自己的推箱子应用程序。MFC综合练习:开发自己的推箱子应用程序。2011-06-05 14:07这是我为了完成这个学期C+课程设计而做的作业,虽说无法达到老师的要求,但是通过这次练习,确实让我获益匪浅。应用的主要技术有:MFC位图操作(双缓存机制)MFC文档读写操作(通过Serialize()虚函数实现)MFC全屏显示功能MFC键盘处理机制。等。这是一个单文档MFC应用程序,主界面如下:地图是我随机生成的,所以有极大的问题,本想加入地图编辑功能,但是快考试没多少时间了,只好作罢。一、准备工作:新建MFC单文档应用程序BOX,添加两个枚
2、举类型到BOXDoc.h enum BoxDirectB_UP,B_DOWN,B_LEFT,B_RIGHT;/表示人物移动的方向enum BoxMapM_NONE,M_WALL,M_DEST;/地图信息标志将所应用到得所有图片资源添加到资源中,ID分别为IDB_BOX、IDB_DEST、IDB_NONE、IDB_PEOPLE、IDB_WALL。VIEW类负责绘图工作,所以所有和绘图相关的变量都放在BOXView类里:CBitmap bitmap1,bitmap2,bitmap3,bitmap4,bitmap5;/位图资源CDC DCBox,DCPeople,DCDest,DCNone,DCWa
3、ll;/代表内存设备资源CSize source1,source2,source3,source4,source5;/分别代表每个位图的尺寸。二、关于游戏信息类的设计。我把它取名为CMap,最初的用意是表示地图,后来陆续又加上各种信息在里面,虽然这个名字不合适,但沿用旧名比较好。class CMap:public CObject public:int*Map;/地图信息CPoint People_Position;/人物的位置信息CPoint*Box_Position;/箱子的位置信息int M;/M、N分别代表地图的列数行数。int N;int BOX_NUM;/代表箱子数目int REAC
4、H_BOX_NUM;/代表已推到目的地的箱子的数目int TOTAL_STATUS;/代表总的关卡数int cur_status;/代表当前关卡数string*status_info;/每个关卡的地图都存放在不同的文件里,status_info代表存放每个地图的文件名称protected:DECLARE_SERIAL(CMap)/赋予该类文档读写能力public:BOOL Is_Move_Ok(int Direct);/判断是否可推BOOL Move_Up(void);/向上推BOOL Move_Down(void);BOOL Move_Left(void);BOOL Move_Right(v
5、oid);BOOL Is_Box(int i,int j);/(i,j)位置处是否为箱子CPoint*GetBoxPosition(int i,int j);/获取(i,j)处得箱子的内存地址,以便移动BOOL InitMap();/初始化地图BOOL DeleteMap();/删除当前地图,以便释放内存资源,供下次读取virtual void Serialize(CArchive&ar);/文档读写;在CBOXDoc类的声明中添加一个CMap对象CMyMap,还有两个函数:public:CMap MyMap;void Next_Status(int cur_status);/下一关inlin
6、e CMap*GetMap()/获取当前游戏信息return&MyMap;三、场景的绘制:首先初始化画图相关资源,在CBOXView类里面的OnInitialUpdate()函数里添加最合适:void CBOXView:OnInitialUpdate()CView:OnInitialUpdate();CClientDC pDC(this);BITMAP bm;bitmap1.LoadBitmap(IDB_BOX);DCBox.CreateCompatibleDC(&pDC);DCBox.SelectObject(&bitmap1);bitmap1.GetObject(sizeof(bm),&b
7、m);source1.cx=bm.bmWidth;source1.cy=bm.bmHeight;bitmap2.LoadBitmap(IDB_PEOPLE);DCPeople.CreateCompatibleDC(&pDC);DCPeople.SelectObject(&bitmap2);bitmap2.GetObject(sizeof(bm),&bm);source2.cx=bm.bmWidth;source2.cy=bm.bmHeight;bitmap3.LoadBitmap(IDB_WALL);DCWall.CreateCompatibleDC(&pDC);DCWall.SelectOb
8、ject(&bitmap3);bitmap3.GetObject(sizeof(bm),&bm);source3.cx=bm.bmWidth;source3.cy=bm.bmHeight;bitmap4.LoadBitmap(IDB_DEST);DCDest.CreateCompatibleDC(&pDC);DCDest.SelectObject(&bitmap4);bitmap4.GetObject(sizeof(bm),&bm);source4.cx=bm.bmWidth;source4.cy=bm.bmHeight;bitmap5.LoadBitmap(IDB_NONE);DCNone.
9、CreateCompatibleDC(&pDC);DCNone.SelectObject(&bitmap5);bitmap5.GetObject(sizeof(bm),&bm);source5.cx=bm.bmWidth;source5.cy=bm.bmHeight;当然在CBOXView类的析构函数里要是放这些资源:CBOXView:CBOXView()DCBox.DeleteDC();DCPeople.DeleteDC();DCDest.DeleteDC();DCNone.DeleteDC();DCWall.DeleteDC();bitmap1.DeleteObject();bitmap2
10、.DeleteObject();bitmap3.DeleteObject();bitmap4.DeleteObject();bitmap5.DeleteObject();处理绘图的是CBOXView的OnDraw函数:void CBOXView:OnDraw(CDC*pDC)CBOXDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);CRect rect;GetClientRect(&rect);/取得整个窗口尺寸CMap*MyMap=pDoc-GetMap();/取得地图信息int Dest_Width=rect.Width()/MyMap-M;/计算显示每个
11、位图资源的宽度和高度int Dest_Heigth=rect.Height()/MyMap-N;int i=0,j=0;for(i=0;i MyMap-M;i+)for(j=0;j MyMap-N;j+)switch(*MyMap).Mapij)case M_NONE:pDC-StretchBlt(i*Dest_Width,j*Dest_Heigth,Dest_Width,Dest_Heigth,&DCNone,0,0,source1.cx,source1.cy,SRCCOPY);break;case M_WALL:pDC-StretchBlt(i*Dest_Width,j*Dest_Heig
12、th,Dest_Width,Dest_Heigth,&DCWall,0,0,source2.cx,source2.cy,SRCCOPY);break;case M_DEST:pDC-StretchBlt(i*Dest_Width,j*Dest_Heigth,Dest_Width,Dest_Heigth,&DCDest,0,0,source3.cx,source3.cy,SRCCOPY);break;for(i=0;i MyMap-BOX_NUM;i+)/绘制箱子pDC-StretchBlt(*MyMap).Box_Positioni.x*Dest_Width,(*MyMap).Box_Posi
13、tioni.y*Dest_Heigth,Dest_Width,Dest_Heigth,&DCBox,0,0,source4.cx,source4.cy,SRCCOPY);/绘制人物pDC-StretchBlt(*MyMap).People_Position.x*Dest_Width,(*MyMap).People_Position.y*Dest_Heigth,Dest_Width,Dest_Heigth,&DCPeople,0,0,source5.cx,source5.cy,SRCCOPY);if(MyMap-REACH_BOX_NUM=MyMap-BOX_NUM)/判断本关是否结束。Mess
14、ageBox(你很强,你赢了!,You Got it!,MB_OK);MyMap-cur_status+;/代表当前关卡的变量自动+1 MyMap-DeleteMap();pDoc-Next_Status(MyMap-cur_status);Invalidate(TRUE);四、文档的读写绘制地图的前提是已经从文件中读取到了地图信息,文件读取采用MFC的Serialize()函数,代表地图的文件内容如下(采用TDump工具查看内容):第一行的08 00 00 00 04 00 00 00 02 00 00 00 01 00 00 00其中08、04代表地图有八列四行。绘制出的信息如下:有两个箱
15、子。以下列出CBoxDoc和CMAP类的Serialize()函数IMPLEMENT_SERIAL(CMap,CObject,1);void CBOXDoc:Serialize(CArchive&ar)if(ar.IsStoring()MyMap.Serialize(ar);else MyMap.Serialize(ar);void CMap:Serialize(CArchive&ar)if(ar.IsStoring()/保存地图ar M;ar N;ar BOX_NUM;int i,j;for(i=0;i M;i+)for(j=0;j N;j+)ar Mapij;ar People_Posit
16、ion;for(i=0;i BOX_NUM;i+)ar Box_Positioni;else/读取地图ar M;/读行列值ar N;ar BOX_NUM;/读取箱子数目InitMap();/给存放地图信息的变量分配内存空间int i,j;for(i=0;i M;i+)for(j=0;j N;j+)ar Mapij;ar People_Position;for(i=0;i BOX_NUM;i+)ar Box_Positioni;为了保证一打开游戏就有得玩,必须在CBOXDoc的构造函数里初始化地图信息:CBOXDoc:CBOXDoc()MyMap.cur_status=0;ifstream re
17、adinfo(Status.info);readinfo MyMap.TOTAL_STATUS;MyMap.status_info=new stringMyMap.TOTAL_STATUS;for(int i=0;i MyMap.TOTAL_STATUS;i+)readinfo MyMap.status_infoi;Next_Status(MyMap.cur_status);readinfo.close();由于每一关都有一个地图,有与之对应的文件,Status.info文件就存在着这些保存着地图信息的文件名列表,Status.info文件内容如下:Map1.Map Map2.Map Map3
18、.Map Map4.Map Map5.Map切换关卡的是Next_Status函数void CBOX:Next_Status(int cur_status)if(MyMap.cur_status=MyMap.TOTAL_STATUS)MessageBox(NULL,不好意思,关卡完了!n关卡将重置!,game over!,MB_OK);MyMap.cur_status=0;CFileException fe;CFile*pFile=GetFile(MyMap.status_infoMyMap.cur_status.c_str(),CFile:modeRead|CFile:shareDenyWr
19、ite,&fe);DeleteContents();SetModifiedFlag();CArchive loadArchive(pFile,CArchive:load);loadArchive.m_pDocument=this;loadArchive.m_bForceFlat=FALSE;CWaitCursor wait;if(pFile-GetLength()!=0)Serialize(loadArchive);loadArchive.Close();ReleaseFile(pFile,FALSE);其中之前出现的InitMap和DeleteMap定义如下:BOOL CMap:InitMa
20、p()Map=new int*M;for(int i=0;i M;i+)Mapi=new intN;Box_Position=new CPointBOX_NUM;REACH_BOX_NUM=0;return TRUE;BOOL CMap:DeleteMap()for(int i=0;i M;i+)delete Mapi;delete Map;delete Box_Position;return TRUE;五、响应键盘消息:负责处理键盘消息的是在CBOCView类的OnChar函数:void CBOXView:OnChar(UINT nChar,UINT nRepCnt,UINT nFlags)
21、CBOXDoc*pDoc=GetDocument();CMap*MyMap=pDoc-GetMap();switch(nChar)case 97:case 65:if(MyMap-Is_Move_Ok(B_LEFT)MyMap-Move_Left();break;case 83:case 115:if(MyMap-Is_Move_Ok(B_DOWN)MyMap-Move_Down();break;case 68:case 100:if(MyMap-Is_Move_Ok(B_RIGHT)MyMap-Move_Right();break;case 87:case 119:if(MyMap-Is_M
22、ove_Ok(B_UP)MyMap-Move_Up();break;case VK_ESCAPE:/esc键,和全屏显示效果有关。CMainFrame*pFrame=(CMainFrame*)AfxGetApp()-m_pMainWnd;/调用主窗口类的自定义函数EndFullScreen,便可退出全屏显示状态pFrame-EndFullScreen();/default:goto INVALID;Invalidate(TRUE);INVALID:CView:OnChar(nChar,nRepCnt,nFlags);六、全屏显示效果:添加一个ID为ID_FULL_SCREEN的菜单项,添加处理
23、这个菜单项的消息处理函数void CMainFrame:OnFullScreen()详细步骤点击链接MFC全屏显示技术七、人物、箱子的移动函数:BOOL CMap:Is_Box(int i,int j)for(int k=0;k BOX_NUM;k+)if(Box_Positionk.x=i&Box_Positionk.y=j)return TRUE;return FALSE;BOOL CMap:Is_Move_Ok(int Direct)int curx=People_Position.x;int cury=People_Position.y;switch(Direct)case B_UP:
24、if(cury=0|(Mapcurxcury-1=M_WALL)|(Is_Box(curx,cury-1)&(cury-1=0|(Mapcurxcury-2=M_WALL)|Is_Box(curx,cury-2)return FALSE;break;case B_DOWN:if(cury=N-1|(Mapcurxcury+1=M_WALL)|(Is_Box(curx,cury+1)&(cury+1=N-1|(Mapcurxcury+2=M_WALL)|Is_Box(curx,cury+2)return FALSE;break;case B_LEFT:if(curx=0|(Mapcurx-1cu
25、ry=M_WALL)|(Is_Box(curx-1,cury)&(curx-1=0|(Mapcurx-2cury=M_WALL)|Is_Box(curx-2,cury)return FALSE;break;case B_RIGHT:if(curx=M-1|(Mapcurx+1cury=M_WALL)|(Is_Box(curx+1,cury)&(curx+1=0|(Mapcurx+2cury=M_WALL)|Is_Box(curx+2,cury)return FALSE;break;return TRUE;CPoint*CMap:GetBoxPosition(int i,int j)for(in
26、t k=0;k BOX_NUM;k+)if(Box_Positionk.x=i&Box_Positionk.y=j)return&Box_Positionk;return NULL;BOOL CMap:Move_Up(void)int curx=People_Position.x;int cury=People_Position.y;People_Position.y-=1;if(Mapcurxcury-1=M_DEST&Is_Box(curx,cury-1)REACH_BOX_NUM-=1;if(Is_Box(curx,cury-1)CPoint*temp=GetBoxPosition(cu
27、rx,cury-1);temp-y-=1;if(Mapcurxcury-2=M_DEST)REACH_BOX_NUM+=1;return TRUE;BOOL CMap:Move_Down(void)int curx=People_Position.x;int cury=People_Position.y;People_Position.y+=1;if(Is_Box(curx,cury+1)&Mapcurxcury+1=M_DEST)REACH_BOX_NUM-=1;if(Is_Box(curx,cury+1)CPoint*temp=GetBoxPosition(curx,cury+1);tem
28、p-y+=1;if(Mapcurxcury+2=M_DEST)REACH_BOX_NUM+=1;return TRUE;BOOL CMap:Move_Left(void)int curx=People_Position.x;int cury=People_Position.y;People_Position.x-=1;if(Is_Box(curx-1,cury)&Mapcurx-1cury=M_DEST)REACH_BOX_NUM-=1;if(Is_Box(curx-1,cury)CPoint*temp=GetBoxPosition(curx-1,cury);temp-x-=1;if(Mapc
29、urx-2cury=M_DEST)REACH_BOX_NUM+=1;return TRUE;BOOL CMap:Move_Right(void)int curx=People_Position.x;int cury=People_Position.y;People_Position.x+=1;if(Is_Box(curx+1,cury)&Mapcurx+1cury=M_DEST)REACH_BOX_NUM-=1;if(Is_Box(curx+1,cury)CPoint*temp=GetBoxPosition(curx+1,cury);temp-x+=1;if(Mapcurx+2cury=M_DEST)REACH_BOX_NUM+=1;return TRUE;这个程序有些复杂,有时间我会上传源代码供大家下载
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1