SDUST 小學期飛機大戰講解 - 1框架
2020-07-28
- 版權宣告:原創文章,未經博主允許不得轉載
這章主要描述下飛機大戰的整體架構。這章開始,內容將基於我的 V2.0.0
大體的認識
這裡所闡述的過程是通用的,是和老師提供的模板程式一樣的,但是程式碼會有些許不同。
產生一個MFC視窗很容易,先從CWinApp派生一個應用程式類,然後再從這個應用程式類建立應用程式物件(theApp)。兩個過程可以容易地在原始碼中找到:
/*PlaneGame.h line16*/ class CPlaneGameApp : public CWinApp { public: CPlaneGameApp(); // 重寫 public: virtual BOOL InitInstance(); // 實現 afx_msg void OnAppAbout(); DECLARE_MESSAGE_MAP() afx_msg void OnHowto(); afx_msg void OnScore(); }; /*PlaneGame.cpp line67*/ CPlaneGameApp theApp;
隨後從CView派生CPlaneGameView,並呼叫OnInitialUpdate()方法:
/*PlaneGameView.cpp line125*/
void CPlaneGameView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: 在此新增專用程式碼和/或呼叫基類
//初始化遊戲
InitGame();
}
可以看到,我們在這裡呼叫了 InitGame()
函式。你會發現正是這個函式,建立了很多遊戲所需的物件,並啟動了遊戲。
MFC程式是由事件驅動的。當一個事件產生,程式將呼叫相對應的事件處理函式;而沒有事件產生時,它將不會做任何額外的事情。我們知道,飛機大戰需要不斷自動移動飛機和子彈,也就是說我們需要不斷產生一個事件,使畫面重新整理、物件移動。所以我們需要啟動一個定時器,不斷產生一個 WM_TIMER 事件,並使它不斷呼叫 OnTimer()
/*PlaneGameView.cpp line795*/
//它本來在InitGame()中,需要實現其他功能而移動了位置
SetTimer(1, 30, NULL);
/*PlaneGameView.cpp line710*/
void CPlaneGameView::OnTimer(UINT_PTR nIDEvent)
{
//重新整理遊戲幀畫面: 在記憶體DC上繪圖
UpdateFrame(m_pMemDC);
AI();
CView::OnTimer(nIDEvent);
}
UpdateFrame()
用於重新整理影象,而 AI()
用於響應鍵盤事件和處理各種亂七八糟的事情。整個程式在定時器的作用下不斷重複呼叫這兩個函式,使整個遊戲執行起來,直到遊戲結束,程式被退出。退出時會產生 WM_DESTROY 事件,並呼叫 OnDestry()
/*PlaneGameView.cpp line719*/
void CPlaneGameView::OnDestroy()
{
CView::OnDestroy();
this->StopGame();
// TODO: 在此處新增訊息處理程式程式碼
}
/*PlaneGameView.cpp line132*/
void CPlaneGameView::StopGame()
{
delete m_pMe;
delete m_pFriend;
delete m_pMemDC;
delete m_pDC;
delete m_pMemBitmap;
}
在 InitGame()
函式中被建立的物件都將在 StopGame()
函式中被釋放。這裡需要注意的是, delete
一個空指標並不會產生錯誤。通讀程式後可以發現, m_pMe 和 m_pFriend 大部分時候都被 delete
了兩遍,因此在第一次 delete
時,我們需要將它置為 NULL
,否則會成為野指標並在第二次 delete
時產生段錯誤。
幾點不同
由於我的修改,整個程式的執行和老師提供的模板程式有幾點不同。
- OnCreate() 函式
為了在遊戲開始之前有一個介面,供玩家選擇模式,我為 WM_CREATE 事件添加了事件處理函式。這主要是指導程式產生視窗用的,動態建立了按鈕。程式碼比較長便不全貼上:
/*PlaneGameView.cpp line726*/
int CPlaneGameView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{...}
通過訊息對映(作用是將各個控制元件產生的事件和與之對應的訊息處理函式繫結),對映到 OnButtonClick()
函式,對不同的模式初始化一些變數,並釋放這些不再需要的按鈕:
void CPlaneGameView::OnButtonClick(UINT uID)
{
switch (uID) {
case ...: {
...
}
default:
break;
}
//啟動遊戲
SetTimer(1, 30, NULL);
delete button1;
delete button2;
delete button3;
delete button4;
button1 = button2 = button3 = button4 = NULL;
}
容易發現,我是在按鈕被按下後再啟動遊戲的。
- pauseGame() 函式
我們能啟動一個定時器,當然也能停止一個計時器。 KillTimer()
就是用來停止一個計時器。 SetTimer(1, 30, NULL);
中,第一個引數是定時器的標識,我們用 KillTimer(<標識>)
即可停止這個計時器:
/*PlaneGameView.cpp line804*/
void CPlaneGameView::pauseGame()
{
KillTimer(1);
CPauseDlg pauseDlg;
pauseDlg.DoModal();
}
pauseDlg
是一個對話方塊,提示遊戲已經暫停是否繼續。這裡需要注意的是, SetTimer()
並不是任何地方都可以呼叫的,它更像是 CPlaneGameView
的一個方法。所以我在某個合適的時候儲存了 CView 物件的指標,通過指標來呼叫 SetTimer()
以實現遊戲的繼續。
本章完
by SDUST weilinfox
本文地址 https://www.cnblogs.com/weilinfox/p/13390862.html
續章 未編輯