MFC的作业
要求
使用MFC的文本视图框架来写,实现贪吃蛇的基本功能:食物随机出现,键盘操作,蛇吃食物变长,蛇撞到边界和自己游戏结束,添加蛇身速度选择的按钮控件。
### 代码实现 SnakeDoc.h和SnakeDoc.cpp中的变量声明与初始化如下:
蛇和食物用两个结构体来表示,snake[]结构体中包含了蛇的坐标和蛇身的长度(蛇是用方块组成,简单来说length表示构成蛇的方块数)。food结构体中包含了食物的坐标和食物是否出现的状态。
视图类中的代码是这样的:
void CSnakeView::OnDraw(CDC* pDC)
{
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(20,20,"Hsmouc");
pDC->TextOut(20,50,"Ocean University of China");
CBrush DrawBrush=(RGB(130,130,0));
CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);
for(int i = 0 ; i <= pDoc->snake[0].length-1 ; i++){
pDC->Rectangle(pDoc->snake[i].body_x*20,pDoc->snake[i].body_y*20,(pDoc->snake[i].body_x+1)*20,(pDoc->snake[i].body_y+1)*20);
}
pDC->SelectObject(DrawBrush);
// TODO: add draw code for native data here
}
void CSnakeView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
switch(nChar){
case VK_UP:
if(pDoc->snake[0].direction != 2){
pDoc->snake[0].direction = 1;
}
break;
case VK_DOWN:
if(pDoc->snake[0].direction != 1){
pDoc->snake[0].direction = 2;
}
break;
case VK_LEFT:
if(pDoc->snake[0].direction != 4){
pDoc->snake[0].direction = 3;
}
break;
case VK_RIGHT:
if(pDoc->snake[0].direction != 3){
pDoc->snake[0].direction = 4;
}
break;
}
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CSnakeView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDC *pDC = GetDC();
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CRect rectClient;
GetClientRect(&rectClient);
if(pDoc->snake[0].body_x*20 <= rectClient.left || pDoc->snake[0].body_x*20 >= rectClient.right || pDoc->snake[0].body_y*20 <= rectClient.top || pDoc->snake[0].body_y*20 >= rectClient.bottom){
KillTimer(1);
AfxMessageBox("233");
InvalidateRect(rectClient);
pDoc->gameReset();
}
if(pDoc->snake[0].length > 3){
for(int temp = pDoc->snake[0].length-1 ; temp > 0 ; temp--){
if(pDoc->snake[0].body_x*20==pDoc->snake[temp].body_x*20 && pDoc->snake[0].body_y*20 == pDoc->snake[temp].body_y*20){
KillTimer(1);
AfxMessageBox("233");
InvalidateRect(rectClient);
pDoc->gameReset();
}
}
}
pDC->SelectStockObject(WHITE_PEN);
pDC->Rectangle(pDoc->snake[pDoc->snake[0].length-1].body_x*20,pDoc->snake[pDoc->snake[0].length-1].body_y*20,(pDoc->snake[pDoc->snake[0].length-1].body_x+1)*20,(pDoc->snake[pDoc->snake[0].length-1].body_y+1)*20);
for(int i=pDoc->snake[0].length-1 ; i > 0 ; i--){
pDoc->snake[i].body_x = pDoc->snake[i-1].body_x;
pDoc->snake[i].body_y = pDoc->snake[i-1].body_y;
}
if(pDoc->snake[0].direction==1){
pDoc->snake[0].body_y--;
}
if(pDoc->snake[0].direction==2){
pDoc->snake[0].body_y++;
}
if(pDoc->snake[0].direction==3){
pDoc->snake[0].body_x--;
}
if(pDoc->snake[0].direction==4){
pDoc->snake[0].body_x++;
}
pDC->SelectStockObject(BLACK_PEN);
CBrush DrawBrush = (RGB(130,130,0));
CBrush *Drawbrush = pDC->SelectObject(&DrawBrush);
pDC->Rectangle(pDoc->snake[0].body_x*20,pDoc->snake[0].body_y*20,(pDoc->snake[0].body_x+1)*20,(pDoc->snake[0].body_y+1)*20);
pDC->SelectObject(DrawBrush);
if(pDoc->snake[0].body_x*20 == pDoc->food.food_x*20 && pDoc->snake[0].body_y*20 == pDoc->food.food_y*20)
{
pDoc->snake[0].length++;
pDoc->food.isfood = true;
pDoc->snake[pDoc->snake[0].length-1].body_x = pDoc->snake[pDoc->snake[0].length-2].body_x;
pDoc->snake[pDoc->snake[0].length-1].body_y = pDoc->snake[pDoc->snake[0].length-2].body_y;
}
if(pDoc->food.isfood == true)
{
srand((unsigned)time(NULL));
do{
for(int temp=pDoc->snake[0].length-1 ; temp >= 0 ; temp--)
if(pDoc->snake[0].body_x*20 == pDoc->snake[temp].body_x*20 && pDoc->snake[0].body_y*20 == pDoc->snake[temp].body_y*20){
pDoc->food.food_x=rand()%25;
pDoc->food.food_y=rand()%25;
for(temp=pDoc->snake[0].length-1 ; temp >= 0 ; temp--){
if(pDoc->food.food_x*20 == pDoc->snake[temp].body_x*20 && pDoc->food.food_y*20 == pDoc->snake[temp].body_y*20){
temp = pDoc->snake[0].length-1;
pDoc->food.food_x=rand()%25;
pDoc->food.food_y=rand()%25;
}
}
}
}while(pDoc->food.food_x*20 < 50 || pDoc->food.food_y*20 < 50 || pDoc->food.food_x*20 > rectClient.right-100 || pDoc->food.food_y*20 > rectClient.right-100);
pDC->Rectangle(pDoc->food.food_x*20,pDoc->food.food_y*20,(pDoc->food.food_x+1)*20,(pDoc->food.food_y+1)*20);
pDoc->food.isfood = false;
}
CView::OnTimer(nIDEvent);
}
void CSnakeView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
void CSnakeView::OnEasy()
{
// TODO: Add your command handler code here
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->startFlag == true){
SetTimer(1,400,NULL);
}
}
void CSnakeView::OnCrazy()
{
// TODO: Add your command handler code here
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->startFlag == true){
SetTimer(1,100,NULL);
}
}
void CSnakeView::OnHard()
{
// TODO: Add your command handler code here
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->startFlag == true){
SetTimer(1,200,NULL);
}
}
void CSnakeView::OnNormol()
{
// TODO: Add your command handler code here
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(pDoc->startFlag == true){
SetTimer(1,300,NULL);
}
}
void CSnakeView::OnStart()
{
// TODO: Add your command handler code here
CSnakeDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->startFlag = true;
SetTimer(1,300,NULL); //normal
}
void CSnakeView::OnPause()
{
// TODO: Add your command handler code here
KillTimer(1);
}
void CSnakeView::OnStop()
{
// TODO: Add your command handler code here
AfxMessageBox("Have a nice day!");
ASSERT(AfxGetApp()->m_pMainWnd != NULL);
AfxGetApp()->m_pMainWnd->SendMessage(WM_CLOSE);
}
让蛇动起来的方式是使用定时器,和以前我做过的卫星和小车大同小异。在这个程序中,蛇前进的方式是通过定时器计时,每过相同的时间,将蛇身部分的位置依次向前传递,用白色的画笔擦去蛇的最后一节。吃食物的时候把食物当成蛇新的头,同时数组长度增加1。
### 小结 这个程序比较繁琐……