水浒传第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);
}