蛇的活動區域由幾個小方塊組成。當這些小方塊是灰色時,它們代表蛇的身體。設整個區域由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);
}