一个简单的吃豆子游戏 (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);
 
}

          这是游戏运行图(太简单了,有点不好意思
)