MFC综合练习 开发自己的推箱子应用程序.docx
《MFC综合练习 开发自己的推箱子应用程序.docx》由会员分享,可在线阅读,更多相关《MFC综合练习 开发自己的推箱子应用程序.docx(15页珍藏版)》请在冰豆网上搜索。
MFC综合练习开发自己的推箱子应用程序
MFC综合练习开发自己的推箱子应用程序。
MFC综合练习:
开发自己的推箱子应用程序。
2011-06-0514:
07这是我为了完成这个学期C++课程设计而做的作业,虽说无法达到老师的要求,但是通过这次练习,确实让我获益匪浅。
应用的主要技术有:
《MFC位图操作》(双缓存机制)
《MFC文档读写操作》(通过Serialize()虚函数实现)
《MFC全屏显示功能》
《MFC键盘处理机制》
。
等。
这是一个单文档MFC应用程序,主界面如下:
地图是我随机生成的,所以有极大的问题,本想加入地图编辑功能,但是快考试没多少时间了,只好作罢。
一、准备工作:
新建MFC单文档应用程序BOX,添加两个枚举类型到BOXDoc.henumBoxDirect{B_UP,B_DOWN,B_LEFT,B_RIGHT};//表示人物移动的方向
enumBoxMap{M_NONE,M_WALL,M_DEST};//地图信息标志
将所应用到得所有图片资源添加到资源中,ID分别为IDB_BOX、IDB_DEST、IDB_NONE、IDB_PEOPLE、IDB_WALL。
VIEW类负责绘图工作,所以所有和绘图相关的变量都放在BOXView类里:
CBitmapbitmap1,bitmap2,bitmap3,bitmap4,bitmap5;//位图资源
CDCDCBox,DCPeople,DCDest,DCNone,DCWall;//代表内存设备资源
CSizesource1,source2,source3,source4,source5;//分别代表每个位图的尺寸。
二、关于游戏信息类的设计。
我把它取名为CMap,最初的用意是表示地图,后来陆续又加上各种信息在里面,虽然这个名字不合适,但沿用旧名比较好。
classCMap:
publicCObjectpublic:
int*Map;//地图信息
CPointPeople_Position;//人物的位置信息
CPoint*Box_Position;//箱子的位置信息
intM;//M、N分别代表地图的列数行数。
intN;
intBOX_NUM;//代表箱子数目
intREACH_BOX_NUM;//代表已推到目的地的箱子的数目
intTOTAL_STATUS;//代表总的关卡数
intcur_status;//代表当前关卡数
string*status_info;//每个关卡的地图都存放在不同的文件里,status_info代表存放每个地图的文件名称
protected:
DECLARE_SERIAL(CMap)//赋予该类文档读写能力
public:
BOOLIs_Move_Ok(intDirect);//判断是否可推
BOOLMove_Up(void);//向上推
BOOLMove_Down(void);
BOOLMove_Left(void);
BOOLMove_Right(void);
BOOLIs_Box(inti,intj);//(i,j)位置处是否为箱子
CPoint*GetBoxPosition(inti,intj);//获取(i,j)处得箱子的内存地址,以便移动
BOOLInitMap();//初始化地图
BOOLDeleteMap();//删除当前地图,以便释放内存资源,供下次读取
virtualvoidSerialize(CArchive&ar);//文档读写
};
在CBOXDoc类的声明中添加一个CMap对象CMyMap,还有两个函数:
public:
CMapMyMap;
voidNext_Status(intcur_status);//下一关
inlineCMap*GetMap()//获取当前游戏信息
return&MyMap;
三、场景的绘制:
首先初始化画图相关资源,在CBOXView类里面的OnInitialUpdate()函数里添加最合适:
voidCBOXView:
OnInitialUpdate()
CView:
OnInitialUpdate();
CClientDCpDC(this);
BITMAPbm;
bitmap1.LoadBitmap(IDB_BOX);
DCBox.CreateCompatibleDC(&pDC);
DCBox.SelectObject(&bitmap1);
bitmap1.GetObject(sizeof(bm),&bm);
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.SelectObject(&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.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.DeleteObject();
bitmap3.DeleteObject();
bitmap4.DeleteObject();;
bitmap5.DeleteObject();;
处理绘图的是CBOXView的OnDraw函数:
voidCBOXView:
OnDraw(CDC*pDC)
CBOXDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
CRectrect;
GetClientRect(&rect);//取得整个窗口尺寸
CMap*MyMap=pDoc-GetMap();//取得地图信息
intDest_Width=rect.Width()/MyMap-M;//计算显示每个位图资源的宽度和高度
intDest_Heigth=rect.Height()/MyMap-N;
inti=0,j=0;
for(i=0;iMyMap-M;i++)
for(j=0;jMyMap-N;j++)
switch((*MyMap).Map[i][j])
caseM_NONE:
pDC-StretchBlt(i*Dest_Width,j*Dest_Heigth,Dest_Width,Dest_Heigth,&DCNone,0,0,source1.cx,source1.cy,SRCCOPY);
break;
caseM_WALL:
pDC-StretchBlt(i*Dest_Width,j*Dest_Heigth,Dest_Width,Dest_Heigth,&DCWall,0,0,source2.cx,source2.cy,SRCCOPY);
break;
caseM_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;iMyMap-BOX_NUM;i++)//绘制箱子
pDC-StretchBlt((*MyMap).Box_Position[i].x*Dest_Width,(*MyMap).Box_Position[i].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)//判断本关是否结束。
MessageBox("你很强,你赢了!
","YouGotit!
",MB_OK);
MyMap-cur_status++;//代表当前关卡的变量自动+1MyMap-DeleteMap();
pDoc-Next_Status(MyMap-cur_status);
Invalidate(TRUE);
四、文档的读写
绘制地图的前提是已经从文件中读取到了地图信息,文件读取采用MFC的Serialize()函数,代表地图的文件内容如下(采用TDump工具查看内容):
第一行的08000000040000000200000001000000其中08、04代表地图有八列四行。
绘制出的信息如下:
有两个箱子。
以下列出CBoxDoc和CMAP类的Serialize()函数
IMPLEMENT_SERIAL(CMap,CObject,1);
voidCBOXDoc:
Serialize(CArchive&ar)
if(ar.IsStoring())
MyMap.Serialize(ar);
elseMyMap.Serialize(ar);
voidCMap:
Serialize(CArchive&ar)
if(ar.IsStoring())//保存地图
arM;
arN;
arBOX_NUM;
inti,j;
for(i=0;iM;i++)
for(j=0;jN;j++)
arMap[i][j];
arPeople_Position;
for(i=0;iBOX_NUM;i++)
arBox_Position[i];
else//读取地图
arM;//读行列值
arN;
arBOX_NUM;//读取箱子数目
InitMap();//给存放地图信息的变量分配内存空间
inti,j;
for(i=0;iM;i++)
for(j=0;jN;j++)
arMap[i][j];
arPeople_Position;
for(i=0;iBOX_NUM;i++)
arBox_Position[i];
为了保证一打开游戏就有得玩,必须在CBOXDoc的构造函数里初始化地图信息:
CBOXDoc:
CBOXDoc()
MyMap.cur_status=0;
ifstreamreadinfo("Status.info");
readinfoMyMap.TOTAL_STATUS;
MyMap.status_info=newstring[MyMap.TOTAL_STATUS];
for(inti=0;iMyMap.TOTAL_STATUS;i++)
readinfoMyMap.status_info[i];
Next_Status(MyMap.cur_status);
readinfo.close();
由于每一关都有一个地图,有与之对应的文件,Status.info文件就存在着这些保存着地图信息的文件名列表,Status.info文件内容如下:
Map1.MapMap2.MapMap3.MapMap4.MapMap5.Map
切换关卡的是Next_Status函数
voidCBOX:
Next_Status(intcur_status)
if(MyMap.cur_status=MyMap.TOTAL_STATUS)
MessageBox(NULL,"不好意思,关卡完了!
\n关卡将重置!
","gameover!
",MB_OK);
MyMap.cur_status=0;
CFileExceptionfe;
CFile*pFile=GetFile(MyMap.status_info[MyMap.cur_status].c_str(),CFile:
modeRead|CFile:
shareDenyWrite,&fe);
DeleteContents();
SetModifiedFlag();
CArchiveloadArchive(pFile,CArchive:
load);
loadArchive.m_pDocument=this;
loadArchive.m_bForceFlat=FALSE;
CWaitCursorwait;
if(pFile-GetLength()!
=0)
Serialize(loadArchive);
loadArchive.Close();
ReleaseFile(pFile,FALSE);
其中之前出现的InitMap和DeleteMap定义如下:
BOOLCMap:
InitMap()
Map=newint*[M];
for(inti=0;iM;i++)
Map[i]=newint[N];
Box_Position=newCPoint[BOX_NUM];
REACH_BOX_NUM=0;
returnTRUE;
BOOLCMap:
DeleteMap()
for(inti=0;iM;i++)
deleteMap[i];
deleteMap;
deleteBox_Position;
returnTRUE;
五、响应键盘消息:
负责处理键盘消息的是在CBOCView类的OnChar函数:
voidCBOXView:
OnChar(UINTnChar,UINTnRepCnt,UINTnFlags)
CBOXDoc*pDoc=GetDocument();
CMap*MyMap=pDoc-GetMap();
switch(nChar)
case97:
case65:
if(MyMap-Is_Move_Ok(B_LEFT))
MyMap-Move_Left();
break;
case83:
case115:
if(MyMap-Is_Move_Ok(B_DOWN))
MyMap-Move_Down();
break;
case68:
case100:
if(MyMap-Is_Move_Ok(B_RIGHT))
MyMap-Move_Right();
break;
case87:
case119:
if(MyMap-Is_Move_Ok(B_UP))
MyMap-Move_Up();
break;
caseVK_ESCAPE:
//esc键,和全屏显示效果有关。
CMainFrame*pFrame=(CMainFrame*)AfxGetApp()-m_pMainWnd;//
//调用主窗口类的自定义函数EndFullScreen,便可退出全屏显示状态
pFrame-EndFullScreen();//
}//
default:
gotoINVALID;
Invalidate(TRUE);
INVALID:
CView:
OnChar(nChar,nRepCnt,nFlags);
六、全屏显示效果:
添加一个ID为ID_FULL_SCREEN的菜单项,添加处理这个菜单项的消息处理函数voidCMainFrame:
OnFullScreen()
详细步骤点击链接《MFC全屏显示技术》
七、人物、箱子的移动函数:
BOOLCMap:
Is_Box(inti,intj)
for(intk=0;kBOX_NUM;k++)
if(Box_Position[k].x==i&&Box_Position[k].y==j)
returnTRUE;
returnFALSE;
BOOLCMap:
Is_Move_Ok(intDirect)
intcurx=People_Position.x;
intcury=People_Position.y;
switch(Direct)
caseB_UP:
if(cury==0||(Map[curx][cury-1]==M_WALL)||(Is_Box(curx,cury-1)&&(cury-1==0||(Map[curx][cury-2]==M_WALL)||Is_Box(curx,cury-2))))
returnFALSE;
break;
caseB_DOWN:
if(cury==N-1||(Map[curx][cury+1]==M_WALL)||(Is_Box(curx,cury+1)&&(cury+1==N-1||(Map[curx][cury+2]==M_WALL)||Is_Box(curx,cury+2))))
returnFALSE;
break;
caseB_LEFT:
if(curx==0||(Map[curx-1][cury]==M_WALL)||(Is_Box(curx-1,cury)&&(curx-1==0||(Map[curx-2][cury]==M_WALL)||Is_Box(curx-2,cury))))
returnFALSE;
break;
caseB_RIGHT:
if(curx==M-1||(Map[curx+1][cury]==M_WALL)||(Is_Box(curx+1,cury)&&(curx+1==0||(Map[curx+2][cury]==M_WALL)||Is_Box(curx+2,cury))))
returnFALSE;
break;
returnTRUE;
CPoint*CMap:
GetBoxPosition(inti,intj)
for(intk=0;kBOX_NUM;k++)
if(Box_Position[k].x==i&&Box_Position[k].y==j)
return&Box_Position[k];
returnNULL;
BOOLCMap:
Move_Up(void)
intcurx=People_Position.x;
intcury=People_Position.y;
People_Position.y-=1;
if(Map[curx][cury-1]==M_DEST&&Is_Box(curx,cury-1))
REACH_BOX_NUM-=1;
if(Is_Box(curx,cury-1))
CPoint*temp=GetBoxPosition(curx,cury-1);
temp-y-=1;
if(Map[curx][cury-2]==M_DEST)
REACH_BOX_NUM+=1;
returnTRUE;
BOOLCMap:
Move_Down(void)
intcurx=People_Position.x;
intcury=People_Position.y;
People_Position.y+=1;
if(Is_Box(curx,cury+1)&&Map[curx][cury+1]==M_DEST)
REACH_BOX_NUM-=1;
if(Is_Box(curx,cury+1))
CPoint*temp=GetBoxPosition(curx,cury+1);
temp-y+=1;
if(Map[curx][cury+2]==M_DEST)
REACH_BOX_NUM+=1;
returnTRUE;
BOOLCMap:
Move_Left(void)
intcurx=People_Position.x;
intcury=People_Position.y;
People_Position.x-=1;
if(Is_Box(curx-1,cury)&&Map[curx-1][cury]==M_DEST)
REACH_BOX_NUM-=1;
if(Is_Box(curx-1,cury))
CPoint*temp=GetBoxPosition(curx-1,cury);
temp-x-=1;
if(Map[curx-2][cury]==M_DEST)
REACH_BOX_NUM+=1;
returnTRUE;
BOOLCMap:
Move_Right(void)
intcurx=People_Position.x;
intcury=People_Position.y;
People_Position.x+=1;
if(Is_Box(curx+1,cury)&&Map[curx+1][cury]==M_DEST)
REACH_BOX_NUM-=1;
if(Is_Box(curx+1,cury))
CPoint*temp=GetBoxPosition(curx+1,cury);
temp-x+=1;
if(Map[curx+2][cury]==M_DEST)
REACH_BOX_NUM+=1;
returnTRUE;
这个程序有些复杂,有时间我会上传源代码供大家下载