c++课程设计.docx
《c++课程设计.docx》由会员分享,可在线阅读,更多相关《c++课程设计.docx(20页珍藏版)》请在冰豆网上搜索。
![c++课程设计.docx](https://file1.bdocx.com/fileroot1/2023-2/4/2f200cbf-05ff-4b01-9037-20a7a59a7966/2f200cbf-05ff-4b01-9037-20a7a59a79661.gif)
c++课程设计
广东工业大学课程设计任务书
题目名称
“猫抓老鼠”游戏设计
学生学院
自动化
专业班级
09级网络工程4班
姓名
孔凡云
学号
3109001405
一、课程设计的内容
1.项目简介:
项目名称:
“猫抓老鼠”游戏设计
项目类型:
娱乐
编程环境:
MicrosoftVisualC++6.0
项目经验:
学习在MFC框架下编程,提升编程综合能力。
项目说明:
本程序采用标准的SDI程序结构,没有考虑有关保存文档的工作,为简单起见,所有的工作都在试图类中完成。
通过定时器消息是老鼠在场地中自动随机运动,通过键盘消息移动猫去抓老鼠。
原理很简单,但为了使运动状态逼真且游戏的逻辑正确、完整、也有一定的难度。
编写这样一个综合面较广的程序对提升C++初学的编程与设计能力是极有帮助的。
2.功能介绍:
(1)通过键盘的上、下、左、右方向键控制猫。
(2)老鼠在窗口中自由活动,可随时改变行走方向,与窗口边界则改变方向。
(3)猫碰到老鼠后就吃掉老鼠(老鼠不再显示),吃掉老鼠后,游戏结束并显示
所剩余时间;
(4)能显示当前时间的老鼠数目和剩余时间值;
(5)可以选择游戏的级别和难度。
3.系统实现概述:
(1)首先用AppWizard生成一个名为CatCatchRat的SDI程序框架。
(2)调出InsertSource对话框,利用位图编辑器分别画出一个方向的猫和老鼠的位图(画猫操作如图1所示),然后把它们复制到其他的方向的位图上并用“Rotate90degrees”命令对其进行旋转。
相应的ID分别为IDB_CatUp、IDB_CatDown、IDB_CatLeft、IDB_CatRight、IDB_RatUp、IDB_RatDown、IDB_RatLeft和IDB_RatRight。
图1
(3)在框架窗口的主菜单(IDR_MAINFRAME)中添加两个下拉选项,一个为“控件”,添加三个菜单选项“开始”、“停止”和“重玩”;另一个为“难度”,添加三个菜单选项“高”、“中”、“低”,删除其他无关的下拉菜单,各菜单属性设置如表1所示:
ID
Caption
IDM_Start
开始
ID_Stop
停止
ID_Resart
重玩
IDM_Hard
高
ID_Normal
中
ID_Easy
低
具体操作如图2所示:
(4)为视图添加菜单选项对应的成员函数。
进入ClassWizard的MessageMaps选项卡,选择ClassName项为CcatCathRatView,在ObjectIDs列表框中分别选择新添加的菜单选项的ID,在Messages列表框中选择COMMAAND,按下AddFunction按钮添加成员函数,然后再在Messages列表中选择UPDATE_COMMAND,按下AddFunction按钮添加另一组成员函数。
如图3所示:
图3
(5)用ClassWizard在视图类中建立定时器的消息处理函数OnTimer(),以及键盘消息处理函数OnKeyDown()。
具体操作如图4所示·:
图4
(6)在相应的函数中写入代码,完成程序;
(7)游戏的运行及输入输出。
游戏者可以选择框架窗口的下拉菜单“难度”中的选项设置难度,选择下拉菜单“控制”中的菜单选项“开始”后,老鼠在场地中随机运动,这时通过四个方向键可以移动猫去抓老鼠,猫身体的任何部分碰到老鼠身体的任何部分则猫吃掉老鼠,该老鼠消失,游戏过程中可以选择菜单选项“停止”暂停。
如果在规定的时间内抓完所有的老鼠则成功,否则失败。
游戏结束后可以选择菜单选项“重玩”重新开始。
场地右边显示剩余的老鼠数目和剩余的游戏时间,如图5所示:
图5
胜利时:
失败时:
4.关键技术:
本程序主要涉及到的知识点有:
键盘消息、菜单、定时器消息、位移显示和移动、位置判断算法。
同时还有判断游戏输赢、设置游戏难度系数、显示文字等工作,有一定的难度和工作量。
该题的难点在于猫和老鼠的的显示。
使老鼠随机移动以及如何判断老鼠被吃掉。
猫和老鼠可以分别用位图画出,显示他们有固定的步骤。
但为了把老鼠和猫的运动模拟得更加逼真,用场要保证脑袋的方向和运动方向一致,这样如果简单地假定只有上、下、左、右四个方向的话,就必须分别使用四幅位图来显示不同方向的猫和老鼠。
我们知道,位图在窗口客户区自动移动可以通过一个定时器消息改变位图所显示的坐标来实现,即当定时器消息到来时,计算位图显示的位置,并在新的位置重新显示位图。
当老鼠和猫位图的显示位置有重合时,则认为老是被吃掉,这里使用了一个不十分精确的简单算法,当猫和老鼠水平方向的位置差小于老鼠的宽度,并且猫和老鼠垂直方向的位置差小于老鼠的高度时,就认为老鼠被抓住。
关键函数具体如下:
(1)在视图类结构函数中添加以下初始化代码,这部分代码除“载入猫和老鼠的位图资源”外,也可以添加到视图类的OnInitilUpdate()函数中。
//载入猫和老鼠的位图资源
m_bmCat[0].LoadBitmap(IDB_CatUp);
m_bmCat[1].LoadBitmap(IDB_CatDown);
m_bmCat[2].LoadBitmap(IDB_CatLeft);
m_bmCat[3].LoadBitmap(IDB_CatRight);
m_bmRat[0].LoadBitmap(IDB_RatUp);
m_bmRat[1].LoadBitmap(IDB_RatDown);
m_bmRat[2].LoadBitmap(IDB_RatLeft);
m_bmRat[3].LoadBitmap(IDB_RatRight);
//计算猫和老鼠位图的搞和宽
BITMAPbmCat;
m_bmCat[2].GetBitmap(&bmCat);
m_nCatw=bmCat.bmWidth;
m_nCath=bmCat.bmHeight;
BITMAPbmRat[4];
m_bmRat[0].GetBitmap(&bmRat[0]);
m_bmRat[1].GetBitmap(&bmRat[1]);
m_bmRat[2].GetBitmap(&bmRat[2]);
m_bmRat[3].GetBitmap(&bmRat[3]);
m_nRatw=bmRat[0].bmWidth;
m_nRath=bmRat[0].bmHeight;
//场地矩形和老鼠数目设置
m_rectClient=CRect(20,20,380,380);
m_nRat=RATMAX;
StartFlag=-1;
//计算猫和老鼠位图的初时位置和运动方向
m_nCatx=m_rectClient.left+m_rectClient.Width()/2;
m_nCaty=m_rectClient.top+m_rectClient.Height()/2;
m_rectCat=CRect(m_nCatx,m_nCaty,m_nCatx+m_nCatw,m_nCaty+m_nCath);
m_nCatDirection=2;
srand((unsigned)time(NULL));
for(inti=0;i{
m_nRatx[i]=m_rectClient.left+rand()%(m_rectClient.Width()-m_nRatw);
m_nRaty[i]=m_rectClient.top+rand()%(m_rectClient.Height()-m_nRath);
m_rectRat[i]=CRect(m_nRatx[i],m_nRaty[i],m_nRatx[i]+m_nRatw,m_nRaty[i]+m_nRath);
m_nRatDirection[i]=rand()%4;
m_bRatLive[i]=TRUE;
}/*FOR*///初始难度设为中
m_nDifficulty=1;
m_timeWork=m_timeSet=20;//游戏时间20秒
m_nCatSpeed=5;
m_nRatSpeed=3;
m_nWinFlag=-1;
(2)在视图类的OnDraw()成员函数中添加以下代码:
//显示游戏状态
CStringstrTime;
CStringstrRat;
strTime.Format("剩余时间:
%2d:
%2d:
%2d",m_timeWork.GetHours(),m_timeWork.GetMinutes(),m_timeWork.GetSeconds());
strRat.Format("待抓老鼠:
%3d",m_nRat);
pDC->TextOut(410,100,strTime);
pDC->TextOut(410,140,strRat);
//显示猫和老鼠
CDCmemDC[RATMAX];
CDCmemCatDC;
CBitmap*pOldDC;
memCatDC.CreateCompatibleDC(NULL);
pOldDC=memCatDC.SelectObject(&m_bmCat[m_nCatDirection]);
pDC->BitBlt(m_nCatx,m_nCaty,m_nCatw,m_nCath,&memCatDC,0,0,SRCAND);
memCatDC.SelectObject(pOldDC);
(3)在键盘、定时器、菜单消息处理函数中写入老鼠和猫移动的相应代码代码。
voidCCatCatchRatView:
:
OnTimer(UINTnIDEvent)
{
if(m_nRat>0)
{
//有老鼠未被抓住
srand((unsigned)time(NULL));
for(inti=0;i{
if(m_bRatLive[i])
{//对未被抓住的老鼠进行处理
switch(nIDEvent)
{
case2:
//该变老鼠运动方向
m_nRatDirection[i]=rand()%4;
break;
case1:
//改变老鼠位置
InvalidateRect(m_rectRat[i]);
intnRatMoveStep=m_nRatSpeed+rand()%5;//老鼠移动的距离
if((abs(m_nRatx[i]-m_nCatx)<3*m_nRatw)
&&(abs(m_nRaty[i]-m_nCaty)<3*m_nRath))
{//如果老鼠靠近了猫就改变方向
m_nRatDirection[i]=rand()%4;
}/*if*/
switch(m_nRatDirection[i])
{case0:
//向上移动
if(m_rectRat[i].top-nRatMoveStep>m_rectClient.top)
{
m_rectRat[i].top-=nRatMoveStep;
m_rectRat[i].bottom-=nRatMoveStep;
m_nRaty[i]-=nRatMoveStep;
}/*if*/
else
{//运动到边界侧改变方向
m_nRatDirection[i]=rand()%4;
}/*else*/
break;
case1:
//向下移动
if(m_rectRat[i].bottom+nRatMoveStep{
m_rectRat[i].top+=nRatMoveStep;
m_rectRat[i].bottom+=nRatMoveStep;
m_nRaty[i]+=nRatMoveStep;
}/*if*/
else
{//运动到边界侧改变方向
m_nRatDirection[i]=rand()%4;
}/*else*/
break;
case2:
//向左移动
if(m_rectRat[i].left-nRatMoveStep>m_rectClient.left)
{
m_rectRat[i].left-=nRatMoveStep;
m_rectRat[i].right-=nRatMoveStep;
m_nRatx[i]-=nRatMoveStep;
}/*if*/
else
{//运动到边界侧改变方向
m_nRatDirection[i]=rand()%4;
}/*else*/
break;
case3:
//向右移动
if(m_rectRat[i].right+nRatMoveStep{
m_rectRat[i].left+=nRatMoveStep;
m_rectRat[i].right+=nRatMoveStep;
m_nRatx[i]+=nRatMoveStep;
}/*if*/
else
{//运动到边界侧改变方向
m_nRatDirection[i]=rand()%4;
}/*else*/
break;
}/*swicth*/
}/*switch*/
//判断运动后是否被猫抓住
if((abs(m_nRatx[i]-m_nCatx){
m_nRat--;
m_bRatLive[i]=false;
}/*if*/
InvalidateRect(m_rectRat[i]);
}/*if*/
}/*for*/
//计算游戏剩余时间
m_timeEnd=m_timeEnd.GetCurrentTime();
m_timeWork=m_timeSet-(m_timeEnd-m_timeStart);
InvalidateRect(CRect(410,100,560,160));
if(!
(m_timeWork.GetTotalSeconds()))
{
KillTimer
(1);
KillTimer
(2);
StartFlag=2;
if(m_nRat>0)
{//游戏时间以到,老鼠还没抓完,失败
m_nWinFlag=1;//MessageBox("猫高一尺,鼠高一丈!
");
}/*if*/
else
{//游戏时间未到,老鼠已经抓完,成功
m_nWinFlag=0;//MessageBox("鼠高一尺,猫高一丈!
");
}/*else*/
Invalidate();
}/*if*/
}/*if*/
elseif(m_timeWork.GetTotalSeconds())
{
KillTimer
(1);
KillTimer
(2);
StartFlag=2;
Invalidate();
m_nWinFlag=0;//MessageBox("鼠高一尺,猫高一丈!
");
}/*elseif*/
CView:
:
OnTimer(nIDEvent);
}
voidCCatCatchRatView:
:
OnRestart()
{
//重新开始游戏的初始化工作,设置初始参数
StartFlag=-1;
m_nRat=RATMAX;
m_timeWork=m_timeSet;
m_nCatDirection=2;
//计算猫和老鼠位图的初时位置和运动方向
m_nCatx=m_rectClient.left+m_rectClient.Width()/2;
m_nCaty=m_rectClient.top+m_rectClient.Height()/2;
m_rectCat=CRect(m_nCatx,m_nCaty,m_nCatx+m_nCatw,m_nCaty+m_nCath);
srand((unsigned)time(NULL));
for(inti=0;i{
m_nRatx[i]=m_rectClient.left+rand()%(m_rectClient.Width()-m_nRatw);
m_nRaty[i]=m_rectClient.top+rand()%(m_rectClient.Height()-m_nRath);
m_rectRat[i]=CRect(m_nRatx[i],m_nRaty[i],m_nRatx[i]+m_nRatw,m_nRaty[i]+m_nRath);
m_nRatDirection[i]=rand()%4;
m_bRatLive[i]=TRUE;
}/*FOR*/
Invalidate();
}
voidCCatCatchRatView:
:
OnStart()
{
if(StartFlag)
{
m_timeStart=m_timeStart.GetCurrentTime();
}/*if*/
SetTimer(1,100,NULL);
SetTimer(2,8000,NULL);
StartFlag=1;
}
voidCCatCatchRatView:
:
OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags)
{
if(StartFlag==1)
{
//游戏开始时猫才可以移动
InvalidateRect(m_rectCat,TRUE);
switch(nChar)
{
caseVK_UP:
//向上移动
if(m_rectCat.top-m_nCatSpeed>m_rectClient.top)
{
m_rectCat.top-=m_nCatSpeed;
m_rectCat.bottom-=m_nCatSpeed;
m_nCaty-=m_nCatSpeed;
m_nCatDirection=0;
}/*if*/
break;
caseVK_DOWN:
//向下移动
if(m_rectCat.bottom-m_nCatSpeed{
m_rectCat.top+=m_nCatSpeed;
m_rectCat.bottom+=m_nCatSpeed;
m_nCaty+=m_nCatSpeed;
m_nCatDirection=1;
}/*if*/
break;
caseVK_LEFT:
//向左移动
if(m_rectCat.left-m_nCatSpeed>m_rectClient.left)
{
m_rectCat.left-=m_nCatSpeed;
m_rectCat.right-=m_nCatSpeed;
m_nCatx-=m_nCatSpeed;
m_nCatDirection=2;
}/*if*/
break;
caseVK_RIGHT:
//向右移动
if(m_rectCat.right+m_nCatSpeed{
m_rectCat.left+=m_nCatSpeed;
m_rectCat.right+=m_nCatSpeed;
m_nCatx+=m_nCatSpeed;
m_nCatDirection=3;
}/*if*/
break;
}/*switch*/
InvalidateRect(m_rectCat,FALSE);
//判断猫的移动后是否抓住老鼠
for(inti=0;i{
if(m_bRatLive[i]&&(abs(m_nRatx[i]-m_nCatx){
m_bRatLive[i]=FALSE;
m_nRat--;
InvalidateRect(m_rectRat[i]);
InvalidateRect(CRect(410,100,560,160));
}/*if*/
}/*for*/
}/*if*/
CView:
:
OnKeyDown(nChar,nRepCnt,nFlags);
}
voidCCatCatchRatView:
:
OnSelect()
{
CSelectDlgdlg;
if(dlg.DoModal()==IDOK)
{
m_nDifficulty=dlg.m_nDifficulty;
switch(m_nDifficulty)
{
case2:
m_nCatSpeed=8;
m_nRatSpeed=2;
m_timeSet=40;
break;
case1:
m_nCatSpeed=5;
m_nRatSpeed=3;
m_timeSet=20;
break;
case0:
m_nCatSpeed=6;
m_nRatSpeed=8;
m_timeSet=10;
break;
default:
AfxMessageBox("Difficultysel