贪吃蛇实验.docx
《贪吃蛇实验.docx》由会员分享,可在线阅读,更多相关《贪吃蛇实验.docx(18页珍藏版)》请在冰豆网上搜索。
贪吃蛇实验
一、实验目的
通过编写贪吃蛇小游戏,加深对VC++6.0MFC编程的理解
二、实验原理
1、改变标题栏文字
1)在CMainFrame:
:
PreCreateWindow函数中添加如下代码:
cs.style&=~FWS_ADDTOTITLE;
2)在CMainFrame:
:
OnCreate函数中添加如下代码:
SetWindowText("贪吃蛇");
2、改变标题栏图标
在CSnakeApp:
:
InitInstance()函数中添加如下代码:
AfxGetMainWnd()->SetIcon(this->LoadIcon(IDI_ICON1),TRUE);
3、窗口不能拖动改变大小
在CMainFrame:
:
PreCreateWindow函数中添加如下代码:
cs.style&=~WS_THICKFRAME;
4、窗口不能最大化
在CMainFrame:
:
PreCreateWindow函数中添加如下代码:
cs.style&=~WS_MAXIMIZEBOX;
5、添加菜单
1)增加CMenu成员变量menu
2)在资源中插入菜单IDR_MENU1,添加相应的菜单项
3)在CMainFrame:
:
OnCreate函数中添加如下代码:
menu.LoadMenu(IDR_MENU1);
this->SetMenu(&menu);
6、换肤
1)将skins,SkinPPWTL.dll,include,lib等文件或文件夹放入snake工程文件夹内
2)工程->设置->link对象/库模版中添加库文件lib/SkinPPWTL.lib
3)在StdAfx.h中添加#include"include\SkinPPWTL.h"
4)将头文件SkinPPWTL.h加载到工程
5)在需要换肤的地方添加skinppLoadSkin(_T("skins\\Phenom.ssk"));
皮肤的式样依赖于.ssk结尾的文件。
7、背景颜色,背景图片
1)在CSnakeView:
:
OnEraseBkgnd(CDC*pDC)中添加如下代码:
//变量m_BGPFlag控制画背景颜色还是背景图片
if(m_BGPFlag==1)
{
CBitmapMemBitmap;
CRectrect;
this->GetClientRect(&rect);
MemBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());
CBitmap*pOldBit=pDC->SelectObject(&MemBitmap);
if(!
m_bmp.m_hObject)
this->m_bmp.LoadBitmap(IDB_BITMAP2);
CBrushm_Brush;
m_Brush.CreatePatternBrush(&m_bmp);
pDC->FillRect(&rect,&m_Brush);
}
else
{
CBrushBrush(m_ViewColor);
//保存旧的brush
CBrush*pOldBrush=pDC->SelectObject(&Brush);
CRectViewClip;
pDC->GetClipBox(&ViewClip);
//画需要的区域
pDC->PatBlt(ViewClip.left,ViewClip.top,ViewClip.Width(),ViewClip.Height(),PATCOPY);
//pDC->SelectObject(pOldBrush);
}
2)以蓝色为例,设置背景为蓝色
建立类向导添加如下代码:
voidCSnakeView:
:
OnBlue()
{
//TODO:
Addyourcommandhandlercodehere
m_BGPFlag=0;
m_ViewColor=RGB(0,0,255);
InvalidateRect(NULL);
this->m_FlagRed=true;
this->m_FlagGreen=true;
this->m_FlagBlue=false;
}
3)点蓝色后变灰不可用
建立类向导添加如下代码:
voidCSnakeView:
:
OnUpdateBlue(CCmdUI*pCmdUI)
{
//TODO:
AddyourcommandupdateUIhandlercodehere
if(this->m_FlagBlue)
pCmdUI->Enable();
else
pCmdUI->Enable(false);
}
4)调色板的实现
建立类向导添加如下代码:
voidCSnakeView:
:
OnColor()
{
//TODO:
Addyourcommandhandlercodehere
m_BGPFlag=0;
CColorDialogcd;
cd.DoModal();
m_ViewColor=cd.GetColor();
InvalidateRect(NULL);
}
5)以大青蛇为例,设置背景图片
建立类向导添加如下代码:
voidCSnakeView:
:
OnBgpqing()
{
//TODO:
Addyourcommandhandlercodehere
m_BGPFlag=1;
m_bmp.DeleteObject();
m_bmp.LoadBitmap(IDB_BITMAP1);
this->m_flagCheckBG=0;
this->Invalidate();
this->UpdateWindow();
}
8、将窗口设为固定大小
在CMainFrame:
:
PreCreateWindow(CREATESTRUCT&cs)函数中添加:
cs.cx=790;
cs.cy=600;
9、食物的实现
食物为CPoint类型的坐标。
1)食物坐标的产生:
食物不能产生在窗口外,蛇身上,墙上,代码如下:
voidCSnakeView:
:
iniAim()
{
intuX,uY;
while
(1)
{
uX=rand()%39;//产生在窗口内
uY=rand()%25;
intuTag=0;
for(inti=0;i<=m_aBody.GetUpperBound();i++)
{
CPointuPoint=m_aBody.GetAt(i);
if(uPoint.x==uX||uPoint.y==uY||uY==8||uY==16)//蛇身上,墙上
{
uTag=1;
break;
}
}
if(uTag==0)
break;
}
m_Aim=CPoint(uX,uY);
}
2)将食物画出来:
画以食物的坐标为左上角边长为20的正方形的内接圆
在CSnakeView:
:
OnDraw(CDC*pDC)中添加代码:
pDC->SelectObject(&brush);
pDC->Rectangle(CRect(m_Aim.x*20,m_Aim.y*20,(m_Aim.x+1)*20,(m_Aim.y+1)*20));
10、蛇的实现
1)蛇坐标的产生:
蛇通过动态数组CArraym_aBody实现,蛇的身体的每一段为CPoint类型的变量,即一个坐标。
初始化时,给蛇四个坐标,在视图区的构造函数(CSnakeView:
:
CSnakeView())和“开始“(voidCSnakeView:
:
OnBegin())中添加如下代码:
m_aBody.RemoveAll();//游戏重新开始时,要把原来蛇身中的坐标全去掉
m_aBody.Add(CPoint(7,4));
m_aBody.Add(CPoint(6,4));
m_aBody.Add(CPoint(5,4));
m_aBody.Add(CPoint(4,4));
2)将蛇画出来(蛇头为自己画的四个方向位图):
在CSnakeView:
:
OnDraw(CDC*pDC)中添加代码:
CBitmapbitmap;
switch(m_Direction)//方向不同,选择不同的蛇头位图
{
case1:
bitmap.LoadBitmap(IDB_BITMAPL);
break;
case2:
bitmap.LoadBitmap(IDB_BITMAPU);
break;
case3:
bitmap.LoadBitmap(IDB_BITMAPR);
break;
case4:
bitmap.LoadBitmap(IDB_BITMAPD);
break;
}
CBrushheadBrush;
headBrush.CreatePatternBrush(&bitmap);
for(inti=0;i<=m_aBody.GetUpperBound();i++)
{
CPointuPoint=m_aBody.GetAt(i);
if(i==0)//画蛇头
{
pDC->FillRect(CRect(uPoint.x*20,uPoint.y*20,(uPoint.x+1)*20,(uPoint.y+1)*20),&headBrush);
pDC->SelectObject(&brush);
}
else//画蛇身
{
pDC->SelectObject(&brush);
pDC->Ellipse(CRect(uPoint.x*20,uPoint.y*20,(uPoint.x+1)*20,(uPoint.y+1)*20));
}
}
11、接受键盘按键,控制蛇的方向
建立类向导,添加键盘按下句柄,在函数CSnakeView:
:
OnKeyDown中添加代码:
switch(nChar)//1,2,3,4分别代表左,上,右,下键
{
caseVK_RIGHT:
{
if(m_Direction==1)//若原来方向为左,不能改为相反方向右
break;
m_Direction=3;
break;
}
caseVK_LEFT:
{
if(m_Direction==3)
break;
m_Direction=1;
break;
}
caseVK_UP:
{
if(m_Direction==4)
break;
m_Direction=2;
break;
}
caseVK_DOWN:
{
if(m_Direction==2)
break;
m_Direction=4;
break;
}
}
this->InvalidateRect(NULL);//方向改变,刷新视图区
this->UpdateWindow();
12、墙的实现
1)墙的坐标产生:
a在CSnakeView中定义CPointwall[20];
b在CSnakeView构造函数中添加代码:
drawwall();
c在CSnakeView类中添加函数drawwall
voidCSnakeView:
:
drawwall()
{
for(inti=0;i<10;i++){
wall[i].x=i;
wall[i].y=8;
}
for(i=10;i<20;i++){
wall[i].x=i;
wall[i].y=16;
}
}
2)将特定的位图加载到画刷画墙,代码如下:
CBitmapbitmapblock;
bitmapblock.LoadBitmap(IDB_BITMAP5);//加载特定位图
CBrushblockBrush;
blockBrush.CreatePatternBrush(&bitmapblock);
for(i=0;i<20;i++)//用特定位图的画刷画墙
pDC->FillRect(CRect(wall[i].x*20,wall[i].y*20,(wall[i].x+1)*20,(wall[i].y+1)*20),&blockBrush);
3)墙的移动
在CSnakeView:
:
OnTimer(UINTnIDEvent)中添加如下代码实现墙的循环移动:
for(i=0;i<20;i++){
wall[i].x=(wall[i].x+1)%39;
}
13、吃到食物后变色
通过三个变量n_red,n_green,n_blue控制:
1)初始化:
在在视图区的构造函数(CSnakeView:
:
CSnakeView())和“开始“(voidCSnakeView:
:
OnBegin())中添加
n_red=0;
n_green=155;
n_blue=155;
2)吃到食物后:
n_red=rand()%255;//随机产生新颜色
n_green=rand()%255;
n_blue=rand()%255;
CBrushbrush=RGB(n_red,n_green,n_blue);//新产生颜色给画刷
14、游戏菜单
1)开始:
voidCSnakeView:
:
OnBegin()
{
//TODO:
Addyourcommandhandlercodehere
PlayMusic();//播放音乐
m_Direction=3;//蛇头向右
m_Count=0;//初始化得分为0
m_aBody.RemoveAll();
m_aBody.Add(CPoint(7,4));
m_aBody.Add(CPoint(6,4));
m_aBody.Add(CPoint(5,4));
m_aBody.Add(CPoint(4,4));
n_red=0;
n_green=155;
n_blue=155;
this->SetTimer(1,200,NULL);//设置计时器
this->InvalidateRect(NULL);//刷新视图区
this->UpdateWindow();
}
2)停止:
voidCSnakeView:
:
OnStop()
{
//TODO:
Addyourcommandhandlercodehere
this->KillTimer
(1);//暂停计时器
StopMusic();//停止音乐
}
3)继续:
voidCSnakeView:
:
OnContinue()
{
//TODO:
Addyourcommandhandlercodehere
this->SetTimer(1,200,NULL);//开启计时器
PlayMusic();//播放音乐
}
4)退出:
voidCSnakeView:
:
OnExit()
{
//TODO:
Addyourcommandhandlercodehere
this->KillTimer
(1);//暂停计时器
if(this->MessageBox("你是否确认退出?
","提示",MB_OKCANCEL|MB_ICONEXCLAMATION)==1)//弹出对话框
PostQuitMessage(0);
}
15、等级
等级是由于timer不同
低级为this->SetTimer(1,200,NULL);
中级为this->SetTimer(1,100,NULL);
高级为this->SetTimer(1,50,NULL);
16、蛇的运动
主要在CSnakeView:
:
OnTimer(UINTnIDEvent)中实现,代码如下:
CPointuPoint=m_aBody.GetAt(0);//得到蛇头坐标
intuTag=0;//撞墙或边界的标志变量,0表示没撞
inti;
for(i=0;i<20;i++){
wall[i].x=(wall[i].x+1)%39;//墙的循环移动
}
for(i=0;i<=m_aBody.GetUpperBound();i++)
{
CPointuPoint1=m_aBody.GetAt(i);
if((uPoint1.x==wall[9].x&&uPoint1.y==wall[9].y)||(uPoint1.x==wall[19].x&&uPoint1.y==wall[19].y))//判断蛇是否被两条墙撞到
{
uTag=1;
break;
}
}
if(uTag==1)//若蛇被撞倒,程序转向A
gotoA;
this->InvalidateRect(CRect(0,8*20,39*20,9*20));//刷新两条墙
this->InvalidateRect(CRect(0,16*20,39*20,17*20));
switch(m_Direction)//根据方向加蛇头坐标
{
case3:
uPoint.x++;
for(i=0;i<20;i++)//判断蛇头是否出边界或撞到墙
{
if(uPoint.x>=39||(uPoint.x==this->wall[i].x&&uPoint.y==this->wall[i].y))
{uTag=1;
break;
}
}
break;
case1:
uPoint.x--;
for(i=0;i<20;i++)
{
if(uPoint.x<0||(uPoint.x==this->wall[i].x&&uPoint.y==this->wall[i].y))
{uTag=1;
break;
}
}
break;
case4:
uPoint.y++;
for(i=0;i<20;i++)
{
if(uPoint.y>=25||(uPoint.x==this->wall[i].x&&uPoint.y==this->wall[i].y))
{uTag=1;
break;
}
}
break;
case2:
uPoint.y--;
for(i=0;i<20;i++)
{
if(uPoint.y<0||(uPoint.x==this->wall[i].x&&uPoint.y==this->wall[i].y))
{uTag=1;
break;
}
}
break;
}
if(uTag==0)//若蛇没撞到墙也没出界,判断蛇是否撞到自己
{
for(inti=0;i<=m_aBody.GetUpperBound();i++)
{
CPointuPoint1=m_aBody.GetAt(i);
if(uPoint1.x==uPoint.x&&uPoint1.y==uPoint.y)
{
uTag=1;
break;
}
}
}
if(uTag==0)//蛇没撞墙,没出界,没撞到自己
{
m_aBody.InsertAt(0,uPoint);//将新蛇头插入
ReDisplay(uPoint);//画出新蛇头
if(uPoint.x==m_Aim.x&&uPoint.y==m_Aim.y)//判断是否吃到食物
{
m_Count++;//分数加一
sndPlaySound("eat.wav",SND_ASYNC);//播放吃到食物的音乐
iniAim();//产生新食物
n_red=rand()%255;//蛇身变色
n_green=rand()%255;
n_blue=rand()%255;
this->InvalidateRect(NULL);//刷新视图区
this->UpdateWindow();
}
Else//没吃到食物,去蛇尾后刷新
{
CPointuPoint1=m_aBody.GetAt(m_aBody.GetUpperBound());
m_aBody.RemoveAt(m_aBody.GetUpperBound());
ReDisplay(uPoint1);
}
}
else//蛇与墙,边界,自己相撞
{
A:
KillTimer
(1);//停止计时器
StopMusic();//停止音乐
charc_Count[10];
itoa(m_Count*10,c_Count,10);//将分数*10转化为字符串
CStringS_Count=c_Count;
CStringmsg="Gameover!
Count:
"+S_Count;
AfxMessageBox(msg);//弹出对话框
InvalidateRect(NULL);
}
17、状态栏右下角显示日期,时间,得分
1)在MainFrm.cpp中的staticUINTindicators[]中添加
IDS_TIME,
IDS_Score,
2)在资源视图中的StringTable中添加ID号为“IDS_TIME“,“IDS_Score”,Caption分别为“时间”“分数”
3)建立CMainFrame类向导添加Timer句柄,代码如下:
voidCMainFrame:
:
OnTimer(UINTnIDEvent)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CTimet=CTime