编程游戏,做蛇。
蛇的活动区域由几个小方块组成。当这些小方块是灰色时,它们代表蛇的身体。设整个区域由m×n个正方形组成,左上角正方形的坐标为(0,0)。一条蛇由几个相邻的方块组成,这些方块的坐标按照从蛇头到蛇尾的顺序存储在一个数组中,代表蛇。当蛇在游戏区域“游动”时,对应的数组操作应该是将新的位置坐标插入数组头,同时删除数组中的最后一个元素。这个工作用一般的数组就可以,但是插入的时候需要自己移动数组中的元素;也可以使用CArray来完成这些任务,CArray的成员函数提供了所需的操作,更加简单。
解决问题
(1)创建一个新项目Snake。选择“单个文档”作为MFC向导的第一步,然后按“完成”结束。
(2)选择ResourceView窗口,打开菜单编辑器,在顶部菜单添加一个名为“游戏”的弹出菜单,在该菜单下添加一个名为“开始”的子菜单,其ID为ID_GAME_START,如图1所示。
图1菜单设计
(3)给刚刚在ClassWizard中编辑的菜单添加一个消息处理函数。打开ClassWizard并选择消息映射页。在类名中选择CSnakeView,在对象ID中选择ID_GAME_ START,在Messages中选择COMMAND,添加一个消息处理程序。
(4)在ClassWizard中增加键盘消息处理功能。打开ClassWizard并选择消息映射页。在类名中选择CSnakeView,在对象ID中选择CSnakeView,在Messages中选择WM_KeyDown,增加一个消息处理函数。
(5)在ClassWizard中为计时器消息添加一个处理程序。打开ClassWizard并选择消息映射页。在类名中选择CSnakeView,在对象ID中选择CSnakeView,在Messages中选择WM_Timer,添加一个消息处理程序。
(6)编辑生成的代码,完成程序。
4.源程序列表
(1)选择“类视图”窗口,双击CSnakeView类,并添加以下成员变量。并添加一个头文件:
# include & ltAfxtempl.h & gt
类CSnakeView:公共CView
{
//这里省略了系统生成的几行代码。
私人:
void重新显示(c point p point);
void IniGame();
void inia im();
int m_nLeft,m_nTop,m_nWidth,m_nHeight,m _ nSize//起始坐标、宽度/高度(方块数)和每个方块的大小。
int m _ nDirect//当前方向
// 1-右,2-左,3-下,4-上
CPoint m _ pAim//当前目标坐标
卡雷& ltCPoint,CPoint & gtm _ aBody//蛇身
int m _ nGameStatus//游戏状态:0-未开始,1-开始。
int m _ nCount//被吃掉的目标数
int m_nTime,m _ nTime 1;//使用时间
};
(2)在CSnakeView。Cpp文件,添加三个成员函数:IniAim、IniGame和ReDiaplay:
//这个函数随机生成一个目标给蛇吃。如果目标恰好与蛇身重合,就会再生。
void CSnakeView::IniAim()
{
int uX,uY;//目标位置
while (1)
{
uX = rand()% m _ n height;
uY = rand()% m _ nWidth;
int uTag = 0;// 0-与蛇身不重合,1-重合。
for(int I = 0;我& lt= m_aBody。GetUpperBound();i++)
{
CPoint uPoint = m_aBody。GetAt(I);
if(upoint . x = = UX | | upoint . y = = uy)//目标与蛇重合。
{
uTag = 1;
打破;
}
}
if (uTag == 0)
打破;
}
m_pAim = CPoint (uX,uY);//生成的目标存储在成员变量中。
}
//这个函数初始化游戏,定义游戏的初始状态。
void CSnakeView::IniGame()
{
//游戏区
m _ nLeft = 20
m _ nTop = 20
m _ nWidth = 40
m _ nHeight = 30
m _ nSize = 10;
//游初始状态
m _ nGameStatus = 0;
m _ n direct = 1;
m _ nCount = 0;
//初始化蛇体
m_aBody。remove all();
m_aBody。Add ( CPoint (2,7));
m_aBody。Add ( CPoint (2,6));
m_aBody。Add ( CPoint (2,5));
m_aBody。Add ( CPoint (2,4));
//定时器清零。
m _ nTime = 0;
m _ ntime 1 = 0;
//初始化随机数生成器
srand((无符号)时间(空));
//生成目标
inia im();
}
//刷新游戏区pPoint处的一个小方块。
void CSnakeView::re display(c point pPoint)
{
invalidate repertiser(CRect(m _ nlef+pPoint。y * m_nSize,m_nTop + pPoint。x * m_nSize,
m _ nlef+(p点。y + 1) * m_nSize,m_nTop + (pPoint。x+1)* m _ nSize));
}
(3)修改CSnakeView的构造函数,完成游戏的初始化。
CSnakeView::CSnakeView()
{
IniGame();
}
(4)在OnDraw中添加代码,显示游戏界面。
void CSnakeView::OnDraw(CDC* pDC)
{
CSnakeDoc * pDoc = get document();
ASSERT _ VALID(pDoc);
// TODO:在此添加本机数据的绘制代码
//绘制游戏区域
pDC->;SelectStockObject(WHITE _ BRUSH);
pDC->;rectangle(CRect(m _ nlef-1,m_nTop - 1,m _ nlef+m _ nWidth * m _ nSize+1,
m _ nTop+m _ n height * m _ nSize+1));
//显示当前经过的时间。
CString uStr
UStr。Format("当前时间:% d ",m _ nTime);
pDC->;TextOut(m _ nlef+m _ nWidth * m _ nSize+30,40,uStr);
//显示当前分数。
UStr。格式("当前分数:% d ",m _ nCount);
pDC->;TextOut(m _ nlef+m _ nWidth * m _ nSize+30,140,uStr);
//显示目标
pDC->;SelectStockObject(lt gray _ BRUSH);
pDC->;rectangle(CRect(m _ nlef+m _ pAim。y * m_nSize,m_nTop + m_pAim。x * m_nSize,
m _ nlef+(m _ pAim。y + 1) * m_nSize,m_nTop + (m_pAim。x+1)* m _ nSize));
//画一条蛇
for(int I = 0;我& lt= m_aBody。GetUpperBound();i++)
{
CPoint uPoint = m_aBody。GetAt(I);
pDC->;rectangle(CRect(m _ nlef+uppoint。y * m_nSize,m _ nTop+uppoint。x * m_nSize,
m _ nlef+(up point。y + 1) * m_nSize,m _ nTop+(uppoint。x+1)* m _ nSize));
}
}
(5)为游戏菜单下开始项的消息映射功能添加代码。
void CSnakeView::OnGameStart()
{
//开始游戏,启动计时器。
IniGame();
m _ nGameStatus = 1;
SetTimer (1,100,空);
invalidate();
}
(6)为键盘按键消息处理功能添加代码。
//根据按下的箭头键设置代表不同方向的值。
void CSnakeView::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
{
开关(nChar)
{
案例38:
m _ n direct = 4;
打破;
案例40:
m _ n direct = 3;
打破;
案例37:
m _ n direct = 2;
打破;
案例39:
m _ n direct = 1;
打破;
}
CView::OnKeyDown(nChar,nRepCnt,nFlags);
}
(7)添加定时器消息处理函数的代码。
void CSnakeView::on timer(UINT nIDEvent)
{
m _ ntime 1++;//计时
If (m_nTime1 == 10) //达到1秒。
{
m _ ntime++;
m _ ntime 1 = 0;
invalidate();
}
CPoint uPoint = m_aBody。GetAt(0);//黑鱼的位置
int uTag = 0;//失败了吗?
Switch (m_nDirect) //判断蛇接下来是否出界。
{
案例1: //右
向上点。y++;
如果(uPoint。y & gt= m_nWidth)
uTag = 1;
打破;
案例2: //左
向上点。y-;
如果(uPoint。y & lt0)
uTag = 1;
打破;
情况3: //向下
向上点。x++;
如果(uPoint。x & gt= m_nHeight)
uTag = 1;
打破;
案例4: //上
向上点。x-;
如果(uPoint。x & lt0)
uTag = 1;
打破;
}
If (uTag ==0) //判断蛇是否碰到了自己。
{
for(int I = 0;我& lt= m_aBody。GetUpperBound();i++)
{
CPoint uPoint1 = m_aBody。GetAt(I);
if (uPoint1。x = = uPoint。x & amp& ampuPoint1.y == uPoint。y)
{
uTag = 1;
打破;
}
}
}
if (uTag == 0)
{
m_aBody。InsertAt (0,uppoint);//新蛇头的位置
重新显示(uppoint);
如果(uPoint。x == m_pAim。x & amp& amp向上点。y == m_pAim。y) //击中目标。
{
m _ ncount++;
inia im();
invalidate();
}
其他
{
CPoint uPoint1 = m_aBody。GetAt (m_aBody。GetUpperBound());
m_aBody。RemoveAt (m_aBody。GetUpperBound());
重新显示(upoint 1);
}
}
否则//游戏结束
{
kill timer(1);
AfxMessageBox("失败!");
}
CView::on timer(nIDEvent);
}