水浒传第42回概括150字:手把手教MFC贪吃蛇

来源:百度文库 编辑:偶看新闻 时间:2024/04/29 20:20:00

13本文作者:唐伯虎  发布于:2010-8-28  分类:MFC编程  点击:766
             很多人学了很久MFC,都不知道到底学了什么。因为他们被很多MFC的书给误导了,时下的MFC的书大部分的章节都是如何运用控件。学来学去还是不知道学到了什么,除了移动控件。我就被这些误导了好久,直到后来我尝试编写这个贪吃蛇,才开始真正理解MFC。
           MFC提供的很多控件,这些只是辅助编程用的,给编好的程序添加个按钮之类的,真正要编写windows程序,归根结底还是要用c++的各种算法实现功能,MFC库则帮助我们从命令行程序过渡到GUI程序。
           接下来我就开始指导贪吃蛇的编写。
          首先,要创建一个基于对话框的mfc程序,取名为Snake,然后开始在这些自动生成的代码中添加自己要实现的功能。
          我是怎么实现蛇的呢?
          我的方法是用GUI绘图画出很多小矩形,这些矩形连在一起,就可以出现一条蛇了。于是我们便要记录每个小矩形的一个点的信息。我用了一个Body类
    class  Body
{
public:int x;
    int y;
    Body* next;
 Body* pre;
  Body(int xx,int yy)
 {
  x=xx;
  y=yy;
  next=NULL;
  pre=NULL;
   }
};
然后还需要食物,我们再建立一个food结构体
struct Food
{
 int x;
    int y;
}food;
有人不禁要问为何body不用结构体呢,这里我主要是想用类的构造函数。
 处理好这些微观问题,我们再来宏观研究这条蛇,我们需要这条蛇可以移动,可以吃食物,所以我们要建立一个snake类,并赋予它有移动,吃食物等的功能
class Snake
{
public:Body*  head;
    void move();
   Snake()
 {
  Body* body1=new Body(0,0);
  Body* body2=new Body(1,0);
  body1->next=body2;
  body2->pre=body1;
  head=body2;
  }
        void creatfood();
 int isGameOver();
 Body* getHead(){return head;}
 void DrawSnake(CDC *pDC);
 void DrawFood(CDC *pDC);
 };
由于食物的随机出现,需要保证不和蛇身重合,所以我们需要调用蛇的信息,所以我们不妨把创建食物的函数也加入到snake类中。
   接下来我们来看看实现这些功能的代码
   void Snake::move()
{
 int xx=0;
 int yy=0;
 switch(direct)
 {
 case 0:{yy=head->y-1;xx=head->x;lastdirect=0;break;}
 case 1:{yy=head->y+1;xx=head->x;lastdirect=1;break;}
 case 2:{xx=head->x-1;yy=head->y;lastdirect=2;break;}
 case 3:{xx=head->x+1;yy=head->y;lastdirect=3;break;}
 }
 nextx=xx;
 nexty=yy;
   if(isGameOver()) return;
 if(food.x==xx&&food.y==yy)
 {
            Body* p=new Body(xx,yy);
             Body* q=new Body(0,0);
  q=head;
  q->next=p;
  p->pre=q;
  
  head=p;
 
  food.x=-1;
  food.y=-1;
 
  creatfood();
  score+=10;
  speed+=10;
}
 else
 {
               Body *p=head;
  while(p->pre)
  {
   p=p->pre;
  }
  while(p->next)
  {
  p->x=p->next->x;
  p->y=p->next->y;
  p=p->next;
 
  }
  head->x=xx;
  head->y=yy;
 }
}
注意move()函数中的case 0 1 2 3分别映射了按键的w、s、a、s键
也即就是上下左右的按键。
void  Snake::creatfood()
{
int t=1;
int x=0;
int y=0;
while(t==1)
{
     x=rand()%20;
     y=rand()%30;
   Body* p=head;
   t=0;
    while(p!=NULL)
  {
   if(p->x==x&&p->y==y)
   {  
    t=1;
   
    break;
   }
   else p=p->pre;
  }
}
food.x=x;food.y=y;
}
int Snake::isGameOver()
{
  Body* p=head;
  if(nextx>19||nextx<0||nexty>29||nexty<0)
   {  
    return 1;
   };
  p=p->pre;
 while(p!=NULL)
 {
 if(p->x==nextx&&p->y==nexty) return 1;
 else p=p->pre;
 }
 
   return 0;
}
void Snake::DrawSnake(CDC* pDC)
{
 CBrush br1;
 br1.CreateSolidBrush(RGB(255,255,255));
 pDC->SelectObject(&br1);
 pDC->Rectangle(10,10,210,310);
 br1.DeleteObject();
 int x;
 int y;
 Body *z=getHead();
 CBrush br;
 br.CreateSolidBrush(RGB(255,0,0));
 pDC->SelectObject(&br);
 while(z!=NULL)
 {
  x=int(z->x);
  y=int(z->y);
  pDC->Rectangle(10*x+12,10*y+12,10*x+20,10*y+20);
  z=z->pre;
 }
 br.DeleteObject();
}
void Snake::DrawFood(CDC* pDC)
{
 if(food.x==-1&&food.y==-1) return ;
 CBrush br;
    br.CreateSolidBrush(RGB(255,0,0));
    pDC->SelectObject(&br);
 pDC->Rectangle(10*food.x+12,10*food.y+12,10*food.x+20,10*food.y+20);
 br.DeleteObject();
}
我们除了画蛇之外,还必须要记录成绩 所以我们再建立画出成绩的函数,并且还要给用户按键提示
void DrawScore(CDC* pDC)
{
 CString s;
 s.Format("分数:%d",score);
 pDC->SetTextColor(RGB(155,155,155));
 pDC->TextOut(222,40,s);}
void DrawInit(CDC* pDC)
{
 pDC->SetTextColor(RGB(222,222,222));
 pDC->TextOut(222,70,"W:上");
 pDC->TextOut(222,100,"S:下");
     pDC->TextOut(222,130,"A:左");
 pDC->TextOut(222,160,"D:右");
}
要想能够实现这些功能 需要先创建一个蛇的实例
 Snake snake;
然后在自动生成的代码 CSnakeDlg::OnPaint()函数中实现蛇的绘画
  CDC *pDC = GetDC();
  DrawInit(pDC);
        snake.creatfood();
  SetTimer(1,speed,NULL);
 snake.move();
 snake.DrawSnake(pDC);
       snake.DrawFood(pDC);
  那么这SetTimer()又是什么呢,这是定时器,我们必须定时刷新界面,才能显示出蛇的移动,吃食
 void CSnakeDlg::OnTimer(UINT nIDEvent)
{
 // TODO: Add your message handler code here and/or call default
    CDC*pDC=GetDC();
 if(snake.isGameOver())
 {
   CBrush br1;
        br1.CreateSolidBrush(RGB(255,255,255));
        pDC->SelectObject(&br1);
        pDC->Rectangle(10,10,210,310);
     br1.DeleteObject();
   CFont font;
    font.CreatePointFont(140,"宋体");
    pDC->SelectObject(&font);
   pDC->SetTextColor(RGB(255,0,0));
      pDC->TextOut(88,50,"游戏失败");
      KillTimer(1);
    }
 else{
 
    snake.move();
 snake.DrawSnake(pDC);
 snake.DrawFood(pDC);
 DrawScore(pDC);
 SetTimer(1,speed,NULL);
 }
 CDialog::OnTimer(nIDEvent);
}