版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、手把手教“MFC版貪吃蛇教程”寫在前面的話本次貪吃蛇教程主要知識點包括以下幾個方面1 CView類中的消息響應2 控件的消息響應3 基于CView類內(nèi)的具體游戲實現(xiàn)4 數(shù)組5 游戲圖形的實現(xiàn)用CDC類實現(xiàn)。本版游戲的具體實現(xiàn)是在CViewl類中實現(xiàn),所以其他類不用添加任何代碼。1 / 38由于此次貪吃蛇需要MFC的開發(fā)環(huán)境,所以打開VisualC+新建一個MFC AppWizard單文檔工程,隨意取名一個工程名稱。本次貪吃蛇基本流程與大體思想1 定義蛇類和食物類,初始化貪吃蛇各項成員變量,包括圖像的出現(xiàn)在屏幕的初始位置,長度,以及蛇的行走方向。食物類的定義包括出現(xiàn)的初始位置,以及食物是否被吃掉
2、的判斷。2 用數(shù)組初始化長度為3的貪吃蛇,并且默認食物未出現(xiàn)3 在CView類上運用MFC提供的Windows消息中WM_TIMER消息,運用OnTimer()函數(shù)讓系統(tǒng)提供一個時鐘節(jié)拍,更新游戲4 具體游戲實現(xiàn),包括蛇撞到自己和圍墻都將使游戲結束,判斷吃豆等,其中還包括根據(jù)蛇的長度來進行游戲難度的改變。5 具體鍵盤游戲操作運用到Windows消息響應中的WM_KEYDOWN,用OnKeyDown()來響應玩家的實際操作。/第一部分 首先在已有工程下的“ClassView”中右鍵CView類添加以下Windows信息1 WM_KEYDOWN2 WM_RBUTTONDOWN3 WM_TIMER再
3、右鍵CView類選擇 “ADD Virtual Funciton”選OnInitialUpdate()OnInitialUpdate()的功能如下:視圖窗口完全建立后第一個被框架調(diào)用的函數(shù)??蚣茉诘谝淮握{(diào)用OnDraw前會調(diào)用OnInitialUpdate,因此OnInitialUpdate是設置滾動視圖的邏輯尺寸和映射模式的最合適的地方。時間上,兩者先后順序不同,構造函數(shù)生成本類的對象,但沒有產(chǎn)生窗口,OnCreate后窗口產(chǎn)生,然后才是視圖的OnInitialUpDate,一般在這里對視圖的顯示做初始化。簡單點,就是ONCREATE只是產(chǎn)生VIEW的基本結構和變量而在OnInitialUp
4、Date()中,主要初始化視圖中控件等。對各個變量進行初始化操作所以我們要用這個函數(shù)來進行貪吃蛇的初始化工作。再者還要添加一個成員函數(shù)oninit()進行貪吃蛇外觀的初始化控件的設計再者是設計游戲的一些控件來控制“游戲開始” “游戲結束” 和“游戲暫?!薄N覀兛梢渣c擊“工作空間”的“ResourceView”進行控件的具體設計,這里我們在Menu文件夾中把“IDR_MAINFRAME”中默認的控件全部刪除右鍵其中的標題欄,點擊屬性,會得到一個菜單欄標題,我們分別建立1個菜單欄標題。這里我們分別建“游戲”。點擊并且在已有控件中的列表中點擊屬性,進行“菜單項目屬性”的設置。我們本別建立的屬性“標明
5、”與對應的ID有游戲開始 IDM_START游戲暫停 IDM_PAUSE游戲繼續(xù) IDM_CONTINUE游戲退出 IDM_EXIT此處控件的設計是“可見即可得”的控件操作成功設置ID之后 我們分別右鍵各項屬性進行消息響應處理函數(shù)的生成具體方法操作例子如下1右鍵“游戲開始”2 點擊“類向導建立”3 在Message Maps頁面,在要進行消息響應的控件ID列表Object IDs中上選擇對應的ID, 這里我們選擇IDM_START,具體實現(xiàn)的環(huán)境是CView類,所以我們必須把“Class name”的默認“CMainFrame”改為“CView類”,并且在“Messages”類型設置中,用“C
6、OMMAND”設置為其為命令消息。其余各項也按照同理進行設置。PS:Windows消息的分類有3種,標準消息,命令消息,通告消息1 標準消息除COMMAND之外,所以WM_開頭都是標準消息2 命令消息就是COMMAND3 通告消息由控件產(chǎn)生的消息,這類信息也能以WM_COMMAND類型出現(xiàn)最后我們回到原來的ClassView去看看我們一共添加的函數(shù)所有的函數(shù)集合全部有以下在此處我們可以看到我們添加的Windows消息所有的 消息響應函數(shù)的聲明/第二部分具體實現(xiàn)游戲、Step 1首先我們在文件開頭處分別定義 蛇 和食物 的全局變量struct Snakeint x,y;int len;int d
7、irect;Snake50;struct Foodint x;int y;int isfood;Food;再者void CSNAKEView:OnInitialUpdate()CView:OnInitialUpdate();Snake0.x=10;Snake0.y=10;Snake1.x=11;Snake1.y=10;Snake2.x=12;Snake2.y=10;Snake0.direct=3;Snake0.len=3;Food.isfood=1;/ TODO: Add your specialized code here and/or call the base class代碼說明:初始化
8、貪吃蛇起初有3個節(jié)點,長度為3,起始坐標;食物默認為 1無0有 當然我更加喜歡0無1有Step 2 對OnKeyDown()具體添加代碼void CSNAKEView:OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)/ TODO: Add your message handler code here and/or call defaultswitch(nChar)case VK_UP:if(Snake0.direct!=2)Snake0.direct=1;break; case VK_DOWN:if(Snake0.direct!=1)Snake0
9、.direct=2;break;case VK_LEFT:if(Snake0.direct!=4)Snake0.direct=3;break; case VK_RIGHT:if(Snake0.direct!=3)Snake0.direct=4;break; CView:OnKeyDown(nChar, nRepCnt, nFlags);CView:OnKeyDown(nChar, nRepCnt, nFlags);OnKeyDown函數(shù)的第一個參數(shù) UINT nChar 是接收用戶鍵入的信息,然后我們用switch進行選擇判斷代碼說明:Snake0代表的是蛇頭,我們對蛇頭的方向Snake0.d
10、irect進行判斷。case VK_UP:if(Snake0.direct!=2)Snake0.direct=1;break; 意思就是當Snake0.direct的方向此時并不等于“下”的時候,才能做出“上”的操作動作,否則則忽略用戶“向上”的操作按鍵效果Step 3 對OnRButtonDown()具體添加代碼void CSNAKEView:OnRButtonDown(UINT nFlags, CPoint point)/ TODO: Add your message handler code here and/or call default/ TODO: Add your message
11、 handler code here and/or call defaultCString str;str.Format("%d,%d",point.x,point.y);AfxMessageBox(str);CView:OnRButtonDown(nFlags, point);CView:OnRButtonDown(nFlags, point);CView:OnRButtonDown(nFlags, point);這個函數(shù)功能是:用鼠標右鍵屏幕,就會馬上顯示當前位置的坐標信息。其實這個函數(shù)并不是本游戲中必要添加的函數(shù),只是為了在后面游戲頁面的設計的時候可以用鼠標右鍵屏幕了
12、解大概的屏幕坐標信息,才特地做的這里補充一個知識點WIN32坐標系有3種1 世界坐標系2 頁面坐標系3 設備坐標系世界坐標系與頁面坐標系稱謂“邏輯空間”,實際上就等同于我們現(xiàn)實生活中的數(shù)學坐標系一樣。設備坐標系則不然,電腦屏幕就是一個用設備坐標系的,特征為以用戶區(qū)窗口左上角為(0 , 0)原點,X坐標向右為正,Y坐標向下為正。Step 4void CSNAKEView:oninit()CDC *pDC=GetDC();CBrush DrawBrush=(RGB(100,100,100);CBrush *Drawbrush=pDC->SelectObject(&DrawBrush)
13、;for(int i=0;i<=snake0.l-1;i+)pDC->Rectangle(snakei.x*20,snakei.y*20,(snakei.x+1)*20,(snakei.y+1)*20);pDC->SelectObject(DrawBrush);代碼說明:利用Windows給我們提供的CDC類來進行畫圖,我們首先用一個指向CDC類的指針去接受與該窗口相關聯(lián)的DC句柄,然后用定義畫刷一個DrawBrush對象,并且用RGB(100,100,100)來給畫刷初始化顏色。并且用SelectObject(&DrawBrush);函數(shù)把對象畫刷選入到設備描述表中
14、,用for循環(huán)依次把貪吃蛇的3個節(jié)點畫出來。void far rectangle(int left, int top, int right, int bottom);這個函數(shù)的的功能根據(jù)函數(shù)功能:該函數(shù)畫一個矩形,用當前的畫筆畫矩形輪廓,用當前畫刷進行填充.Step 5 控件添加代碼void CSNAKEView:OnStart()/ TODO: Add your command handler code hereSetTimer(1,3000,NULL);AfxMessageBox("3秒后開始游戲!");void CSNAKEView:OnPause()/ TODO:
15、Add your command handler code hereKillTimer(1);AfxMessageBox("暫停游戲.");void CSNAKEView:OnExit()/ TODO: Add your command handler code hereAfxMessageBox("退出游戲.");exit 0;void CSNAKEView:OnContinue()/ TODO: Add your command handler code hereSetTimer(1,10,NULL);代碼說明:由于之前我們設定了WM_TIMER消息
16、,我們能運用計時器功能用WM_TIMER來設置定時器先請看SetTimer這個API函數(shù)的原型UINT_PTR SetTimer(HWND hWnd, / 窗口句柄UINT_PTR nIDEvent, / 定時器ID,多個定時器時,可以通過該ID判斷是哪個定時器UINT uElapse, / 時間間隔,單位為毫秒TIMERPROC lpTimerFunc / 回調(diào)函數(shù));SetTimer(m_hWnd,1,1000,NULL); /一個1秒觸發(fā)一次的定時器在MFC程序中SetTimer被封裝在CWnd類中,調(diào)用就不用指定窗口句柄了所以我們這里可以只去后3個參數(shù)寫成SetTimer(1,10,N
17、ULL);1000為1秒關于afxMessageBox的研究在本博客中有寫有,這里就不在贅述Step 6 對OnDraw()的添加代碼OnDraw()函數(shù)眾所周知視圖類中的輸出.視圖類的輸出基本上都是在視圖類的OnDraw函數(shù)中處理的,系統(tǒng)會準備好入?yún)?,然后調(diào)用OnDraw函數(shù)本人也沒有過多的去研究過次函數(shù),僅知道一些皮毛。不過這里有個知識點那便是OnPaint()與OnDraw()的區(qū)別,OnPaint()派生于CWnd類,響應WM_PAINT消息。OnDraw是CView類的成員函數(shù),并且沒有消息響應功能,這就是為什么視圖類沒有只有OnDraw()而沒有OnPaint()的原因。OnDra
18、w()維護視圖客戶區(qū)(例如通過試表在視圖中畫圖),而OnPaint()維護窗口的客戶區(qū)void CSNAKEView:OnDraw(CDC* pDC)CSNAKEDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);/ TODO: add draw code for native data hereCBrush backBrush(RGB(100,100,0);CBrush* pOldBrush = pDC->SelectObject(&backBrush);CRect rect;pDC->GetClipBox(&rect);pD
19、C->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),PATCOPY);pDC->SelectObject(pOldBrush);pDC->Rectangle(19,19,501,501);oninit();代碼說明:此處是用畫刷畫一個背景,并且畫出3個矩形區(qū)域函數(shù)原型:int GetClipBox(HDC hdc, LPRECT lprc);該函數(shù)得到一個能夠完包含當前可見區(qū)域的最小矩形的大小。 函數(shù)原型:int nYLeft, int nWidth, int nHeight, DWORD dwRop);該函數(shù)
20、使用當前選入指定設備環(huán)境中的刷子繪制給定的矩形區(qū)域。Step 7 對OnTime()的添加代碼void CSNAKEView:OnTimer(UINT nIDEvent)/ TODO: Add your message handler code here and/or call defaultCDC *pDC=GetDC();CString soure;if(Snake0.len=2)SetTimer(1,370,NULL);if(Snake0.len=3)SetTimer(1,270,NULL);if(Snake0.len=6)SetTimer(1,200,NULL);if(Snake0.l
21、en=9)SetTimer(1,100,NULL);soure.Format("得分:%d!",(Snake0.len-3)*10); /撞界判斷if(Snake0.x*20<=37|Snake0.y*20<=37|Snake0.x*20>=462|Snake0.y*20>=462)KillTimer(1);AfxMessageBox(soure);/ s=0;/蛇身相撞判斷if(Snake0.len>3)for(int sn=Snake0.len-1;sn>0;sn-)if(Snake0.x*20=Snakesn.x*20&&a
22、mp;Snake0.y*20=Snakesn.y*20)KillTimer(1);AfxMessageBox(soure);/ s=0;/pDC->SelectStockObject(WHITE_PEN);pDC->Rectangle(SnakeSnake0.len-1.x*20,SnakeSnake0.len-1.y*20,(SnakeSnake0.len-1.x+1)*20,(SnakeSnake0.len-1.y+1)*20);for(int i=Snake0.len-1;i>0;i-)Snakei.x=Snakei-1.x;Snakei.y=Snakei-1.y;/行
23、走方向判斷if(Snake0.direct=1)Snake0.y-;if(Snake0.direct=2)Snake0.y+;if(Snake0.direct=3)Snake0.x-;if(Snake0.direct=4)Snake0.x+;pDC->SelectStockObject(BLACK_PEN);CBrush DrawBrush=(RGB(100,100,100);CBrush *Drawbrush=pDC->SelectObject(&DrawBrush);pDC->Rectangle(Snake0.x*20,Snake0.y*20,(Snake0.x+
24、1)*20,(Snake0.y+1)*20);pDC->SelectObject(DrawBrush);/判斷吃豆的條件,撞到就吃if(Snake0.x*20=Food.x*20&&Snake0.y*20=Food.y*20)Snake0.len+;Food.isfood=1;SnakeSnake0.len-1.x=SnakeSnake0.len-2.x;SnakeSnake0.len-1.y=SnakeSnake0.len-2.y;/如果食物被吃了 就生成if(Food.isfood=1)srand(unsigned)time(NULL);dofor(int isfo=
25、Snake0.len-1;isfo>=0;isfo-)if(Snake0.x*20=Snakeisfo.x*20&&Snake0.y*20=Snakeisfo.y*20)Food.x=rand()%;Food.y=rand()%;while(Food.x*20<70|Food.y*20<70|Food.x*20>430|Food.y*20>430);pDC->Rectangle(Food.x*20,Food.y*20,(Food.x+1)*20,(Food.y+1)*20);Food.isfood=0;CView:OnTimer(nIDEve
26、nt);/下面由我來詳細分析代碼if(Snake0.len=2)SetTimer(1,370,NULL);if(Snake0.len=3)SetTimer(1,270,NULL);if(Snake0.len=6)SetTimer(1,200,NULL);if(Snake0.len=9)SetTimer(1,100,NULL);此段代碼的作用是根據(jù)蛇的長度來進行SetTimer()函數(shù)的定義,可以根據(jù)長度來進行游戲難度的設定,如上代碼分別370ms 270ms 200ms 100ms進行一次新的移動。/撞界判斷if(Snake0.x*20<=37|Snake0.y*20<=37|Sn
27、ake0.x*20>=462|Snake0.y*20>=462)KillTimer(1);AfxMessageBox(soure);這里為什么要乘以20呢?由于我們初始化的時候是Snake0.x=10;Snake0.y=10;Snake1.x=11;Snake1.y=10;Snake2.x=12;Snake2.y=10;所以只是把貪吃蛇的起始位置“搬移”到20倍的位置 當然可以等價于Snake0.x=10*20;Snake0.y=10*20;Snake1.x=11*20;Snake1.y=10*20;Snake2.x=12*20;Snake2.y=10*20;蛇的一節(jié)身體為一個矩形
28、塊,這樣表示每個矩形塊只需起點坐標x 和y身體是不斷增長的,所以用數(shù)組存放每一節(jié)的坐標/蛇身相撞判斷if(Snake0.len>3)for(int sn=Snake0.len-1;sn>0;sn-)if(Snake0.x*20=Snakesn.x*20&&Snake0.y*20=Snakesn.y*20)KillTimer(1);AfxMessageBox(soure);/ s=0;這段是最好理解的了,由于判斷蛇自己是否咬到了自己,根據(jù)蛇長sn,進行sn次for sn-1次循環(huán)并且和Snake0.x進行比較(之所以進行sn-1次那肯定是不包括蛇頭而且蛇的長度也必須大
29、于3才會發(fā)生自己咬自己的情況)KillTimer(1);是停止計時器;和之前的SetTime()對應而已AfxMessageBox(soure);這里不深究,總之就是輸出一個原樣輸出內(nèi)容pDC->SelectStockObject(WHITE_PEN);/把白色的“PEN”選入設備進行畫圖pDC->Rectangle(SnakeSnake0.len-1.x*20,SnakeSnake0.len-1.y*20,(SnakeSnake0.len-1.x+1)*20,(SnakeSnake0.len-1.y+1)*20);/讓它去畫最后一個節(jié)點for(int i=Snake0.len-1
30、;i>0;i-)/貪吃蛇的蛇身移動Snakei.x=Snakei-1.x;Snakei.y=Snakei-1.y;這段的知識點要嚴重的說明一下1 為什么要專門用白筆畫最后一個呢?因為我們的游戲界面是用白色的,貪吃蛇移動的時候,肯定是蛇頭向前走一單位,而尾部肯定要“擦除”掉一個單位,那怎么擦除呢?我們只能用和背景色一樣的畫筆。原來蛇的位置和新蛇的位置差一個單位,所以看起來蛇會多一節(jié)身體,所以將蛇的最后一節(jié)用背景色覆蓋SelectStockObject(WHITE_PEN) 讓它起到“消失”最后一個節(jié)點的功能讓我們以為蛇是向前走了。如 假設現(xiàn)在貪吃蛇有4個單位0123SnakeSnake0.len-1.x*20 <=>SnakeSnake0.4-1.x*20 =Snake3.x*20數(shù)組3 恰好是最后一個節(jié)點的下標,別忘了數(shù)組是從0開始算的請仔細領悟2for(int i=Snake0.len-1;i>0;i-)Snakei.x=Snakei-1.x;Snakei.y=Snakei-1.y;進行次數(shù)為"長度-1"次的循環(huán)為什么要進行長度-1次呢?我這里要說明一下,這里是不包括蛇頭的進行的平移,用數(shù)組賦值的方法,把
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2026年西安理工大學附屬中學教師招聘考試備考試題及答案解析
- 河南豫能控股股份有限公司及所管企業(yè)2026屆校園招聘127人考試參考題庫及答案解析
- 2026新疆第十師北屯市公益性崗位招聘14人考試參考試題及答案解析
- 2026北京市大興區(qū)榆垡鎮(zhèn)中心衛(wèi)生院面向社會招聘8人考試參考試題及答案解析
- 2026湖南郴州市第一人民醫(yī)院招聘3人筆試模擬試題及答案解析
- 2026福建華福證券股份有限公司95547熱線客服人員招聘考試參考題庫及答案解析
- 2026年滁州市第二人民醫(yī)院公開招聘勞務派遣人員20名考試備考題庫及答案解析
- 2026年甘肅慶陽西峰區(qū)學院路實驗學校人才儲備23人筆試模擬試題及答案解析
- 2026年臺州市立醫(yī)院公開招聘高層次衛(wèi)技人員28人筆試備考題庫及答案解析
- 2026年福建省順昌縣國有林場招聘10人筆試備考題庫及答案解析
- 廣東省廣州市花都區(qū)2024-2025學年七年級上學期期末考試數(shù)學試卷(含答案)
- 2025年中國對外貿(mào)易中心集團有限公司招聘84人備考題庫完整答案詳解
- 高數(shù)上冊期末考試及答案
- 【生 物】八年級上冊生物期末復習 課件 -2025-2026學年人教版生物八年級上冊
- 備戰(zhàn)一診課件
- 2025年中職裝甲車輛工程技術(車輛維修)技能測試題
- 2025年10月自考03333電子政務概論試題及答案
- 2025年廣東高中學業(yè)水平合格性考試化學試卷試題(含答案解析)
- 三級安全教育考核試題(鋼筋工)
- 臘八蒜的課件
- 2025年70歲以上的老人三力測試題庫附答案
評論
0/150
提交評論