一个简单的吃豆子游戏 (MFC)
这是我的第一个自己写的小游戏,这其中借鉴了很多网上的思路,也向学长,同学寻求了不少的帮助,能最终完成也是出乎了我的意料,虽然它看起来非常的简单,但从这之中我收获巨大。编程是痛苦的,从来没有一步到位的程序,特别是有时候觉得自己就要到达终点,但突然发现原来自己走偏了,此路不通!
每当此时就要重新修改,那种感觉相当难受,然而当做完的时候又会有一种巨大的成就感
。
下面就具体谈谈我对这个游戏的具体思路及其实现方法
吃豆子游戏的基本构思:
1.添加控件的消息响应
2.添加在View类中的消息响应
(在本次游戏中,主要用到了 WM_KEYDOWN ,WM_RBUTTONDOWN 和WM_TIMER)
3.利用CView类实现游戏的具体内容
4.具体实现游戏,包括创建豆子类,嘴类,并实例化(其中豆子实例化为对象数组,因为有多个豆子)以及嘴的图形,撞界判断,吃完食物进行判断等等功能
5.一定注意一个程序永远不可能一步到位,途中必定会遭遇各种错误,所以建议大家一定要走一步看(运行)一步,否则会死的很惨难过
。
具体实现方法:
第一步:创建一个MFC工程(我是用VC++做的微笑,可能版本有点老,不过不要介意
)
如图:
选择单文档,然后双击完成
第二步:添加必要的Windows响应消息,控件以及类和成员函数
在已有工程下的 CView类中添加以下Windows响应信息
1 WM_KEYDOWN
2 WM_RBUTTONDOWN
3 WM_TIMER
并且add一个虚函数OnInitialUpdate()
这个函数是视图窗口建立后第一个被调用的函数,所以我们用这个函数来实现嘴巴和豆子的初始化。
再接下来就是控件的设计了,在Menu文件夹下的IDR_MAINFRAME中可以进行控件的设计。如图:
删除原有的控件后右击“属性”,并分别填写控件名和ID,并选择可否弹出。
其中:
游戏开始 IDM_START
游戏暂停 IDM_PAUSE
游戏继续 IDM_CONTINUE
游戏退出 IDM_EXIT (也可以改为其他的ID)
另外,要在类向导中生成响应函数(同样是右键“建立类向导”):
在CView类下COMMAND双击即可生成响应函数。
最后在CView类中添加一个成员函数oninit()函数
至此,该添加的都已添加,第二部分告一段落。
第三步:为各个函数添加代码,实现各种功能
1.建立豆子类和嘴巴类
class Mouth
{
public:
int x;
int y;
int len;
int direct;
}mouth; //实例化一个嘴巴的对象mouth
class Bean
{
public:
int x;
int y;
int isBean;
}bean[2]; //实例化一个豆子的对象数组(数组中的每一个元素都是对象)
2. 紧接着就在OnInitialUpdate()中进行初始化
void CEatView::OnInitialUpdate() //初始化嘴巴与豆子
{
CView::OnInitialUpdate();
mouth.x=10;
mouth.y=10;
mouth.direct=3; //方向
bean[0].isBean=1; //豆子有无(1有0无)
bean[1].isBean=1; //这里就只创建了两个豆子大笑
// TODO: Add your specialized code here and/or call the base class
}
3.画嘴巴和豆子
CEatView::oninit() //利用CDC类来画嘴和srand()随机生成豆子
{
CDC *pDC=GetDC(); //用一个指向CDC类的指针去接受与该窗口相关联的DC句柄
CBrush DrawBrush=(RGB(100,100,100)); //用定义画刷一个DrawBrush对象
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Pie(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20,mouth.x*20,mouth.y*20,(mouth.x+1)*20,mouth.y*20); //画嘴
srand((unsigned)time(NULL)); //随机生成豆子
for(int i=0;i<2;i++)
{
bean[i].x=rand()%20+2;
bean[i].y=rand()%20+2;
}
for(int j=0;j<2;j++)
{
pDC->Ellipse(bean[j].x*20,bean[j].y*20,(bean[j].x+1)*20,(bean[j].y+1)*20); //豆子是圆形的
}
pDC->SelectObject(DrawBrush);
}
4.实现控件
void CEatView::OnStart()
{
// TODO: Add your command handler code here
SetTimer(1,1000,NULL);
AfxMessageBox("游戏开始");
}
void CEatView::OnPause()
{
// TODO: Add your command handler code here
KillTimer(1);
AfxMessageBox("游戏暂停");
}
void CEatView::OnContinue()
{
// TODO: Add your command handler code here
SetTimer(1,10,NULL);
}
void CEatView::OnExit()
{
// TODO: Add your command handler code here
AfxMessageBox("退出游戏");
exit;
}
5.为OnRButtonDown()添加代码
void CEatView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) //实现嘴的上下左右移动
{
// TODO: Add your message handler code here and/or call default
switch(nChar)
{
case VK_UP:mouth.direct=1;break; //上
case VK_DOWN:mouth.direct=2;break; //下
case VK_LEFT:mouth.direct=3;break; //左
case VK_RIGHT:mouth.direct=4;break; //右
}
CView::OnKeyDown(nChar, nRepCnt, nFlags);
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
我们利用这个函数来实现键盘(上下左右)对嘴的控制
6. 为OnDraw()添加代码
这个函数是用画刷画出背景并且通过调用oninit()函数来画嘴和豆子
void CEatView::OnDraw(CDC* pDC) //画背景
{
CEatDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CBrush backBrush(RGB(100,100,0));
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); //得到一个能够完包含当前可见区域的最小矩形的大小
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);
pDC->SelectObject(pOldBrush);
pDC->Rectangle(19,19,501,501);
oninit();
// TODO: add draw code for native data here
}
7.实现OnTime()的代码(这是最后一步,也是最难的一步
)
void CEatView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC=GetDC();
//撞界判断
if(mouth.x*20<=37||mouth.y*20<=37||mouth.x*20>=462||mouth.y*20>=462)
{
KillTimer(1);
AfxMessageBox("游戏结束"); //??????
// s=0;
}
pDC->SelectStockObject(WHITE_PEN); //重绘
pDC->Rectangle(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20); //用白笔擦除
//判断行走方向,并重绘
if(mouth.direct==1) //上
{
mouth.y--;
pDC->SelectStockObject(BLACK_PEN);
CBrush DrawBrush=(RGB(100,100,100));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Pie(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20,mouth.x*20,mouth.y*20,(mouth.x+1)*20,mouth.y*20);
pDC->SelectObject(DrawBrush);
}
if(mouth.direct==2) //下
{
mouth.y++;
pDC->SelectStockObject(BLACK_PEN);
CBrush DrawBrush=(RGB(100,100,100));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Pie(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20,(mouth.x+1)*20,(mouth.y+1)*20,mouth.x*20,(mouth.y+1)*20);
pDC->SelectObject(DrawBrush);
}
if(mouth.direct==3) //左
{
mouth.x--;
pDC->SelectStockObject(BLACK_PEN);
CBrush DrawBrush=(RGB(100,100,100));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Pie(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20,mouth.x*20,(mouth.y+1)*20,mouth.x*20,mouth.y*20);
pDC->SelectObject(DrawBrush);
}
if(mouth.direct==4) //右
{
mouth.x++;
pDC->SelectStockObject(BLACK_PEN);
CBrush DrawBrush=(RGB(100,100,100));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
pDC->Pie(mouth.x*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20,(mouth.x+1)*20,mouth.y*20,(mouth.x+1)*20,(mouth.y+1)*20);
pDC->SelectObject(DrawBrush);
}
if(mouth.x*20==bean[0].x*20&&mouth.y*20==bean[0].y*20)
{
bean[0].isBean=0;
}
if(mouth.x*20==bean[1].x*20&&mouth.y*20==bean[1].y*20)
{
bean[1].isBean=0;
}
//食物吃完后结束游戏并给出成绩
if((bean[0].isBean==0)&&(bean[1].isBean==0))
{
KillTimer(1);
AfxMessageBox("游戏结束");
}
CView::OnTimer(nIDEvent);
}
这是游戏运行图(太简单了,有点不好意思
)