自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MFC實(shí)現(xiàn)桌面版Flappy Bird

開發(fā) 后端 架構(gòu)
flappy bird由一位來自越南河內(nèi)的獨(dú)立游戲開發(fā)者阮哈東開發(fā),是一款形式簡易但難度極高的休閑游戲。簡單但不粗糙的8比特像素畫面、超級馬里奧游戲中的水管、眼神有點(diǎn)呆滯的小鳥和幾朵白云便構(gòu)成了游戲的一切。你需要不斷控制點(diǎn)擊屏幕的頻率來調(diào)節(jié)小鳥的飛行高度和降落速度,讓小鳥順利地通過畫面右端的通道,如果你不小心擦碰到了通道的話,游戲便宣告結(jié)束。

一、開發(fā)背景:

flappy bird由一位來自越南河內(nèi)的獨(dú)立游戲開發(fā)者阮哈東開發(fā),是一款形式簡易但難度極高的休閑游戲。簡單但不粗糙的8比特像素畫面、超級馬里奧游戲中的水管、眼神有點(diǎn)呆滯的小鳥和幾朵白云便構(gòu)成了游戲的一切。你需要不斷控制點(diǎn)擊屏幕的頻率來調(diào)節(jié)小鳥的飛行高度和降落速度,讓小鳥順利地通過畫面右端的通道,如果你不小心擦碰到了通道的話,游戲便宣告結(jié)束。

這款虐心的小游戲一經(jīng)推出,便引起火爆的下載。然后先后出現(xiàn)了各種平臺的移植開發(fā):IOS平臺PC和手機(jī)版、采用HTML5+Canvas及Javascript技術(shù)來實(shí)現(xiàn)的Flappy Bird電腦版、以網(wǎng)頁html5+JS技術(shù)完全克隆了原版native app的Web App版、實(shí)現(xiàn)了在微信朋友圈和QQ空間中的無縫運(yùn)行的微信/QQ空間版、WindowsPhone版….但是唯一沒有的是直接可在windows操作系統(tǒng)下的單機(jī)版,于是當(dāng)時突發(fā)奇想,不如我來填補(bǔ)這個漏洞吧!

二、開發(fā)語言及運(yùn)行環(huán)境:

此PC版采用C++的MFC技術(shù)在VS2012開發(fā)平臺下寫成,支持windows 7\8環(huán)境,XP不知道為啥不行~

三、效果展示:

[[124092]]

 [[124093]]

 [[124094]]

 [[124095]]

四、游戲框架說明:

整個游戲除了由MFC游戲基本框架CMyApp和CMainWindow外,這里特別封裝了以下幾個類:

  1. 1、  Bird類[專門處理鳥的飛行邏輯、碰撞檢測、音樂播放、貼圖] 
  2. 2、  PipeList類[內(nèi)嵌Pipe類,并用CList創(chuàng)建一個Pipe鏈表,用來處理游戲中管道的移動邏輯、碰撞檢測等] 
  3. 3、  Panel類[主要是計分板的動畫效果邏輯和計分板的計分邏輯,數(shù)字貼圖,金幣種類運(yùn)算等] 
  4. 4、  Land類[主要處理陸地運(yùn)動邏輯及貼圖] 
  5. 5、  Button類[主要處理按鈕的動畫效果、貼圖及響應(yīng)] 
  6. 6、  Pic類[是圖片資源類,主要負(fù)責(zé)存儲、加載、全局調(diào)用游戲的圖片資源] 

 

五、游戲狀態(tài)及邏輯說明:

這款游戲本身操作簡單、邏輯分明,大致可分為以下幾種狀態(tài):

1、  初始態(tài):基本上為靜態(tài)貼圖,只有鳥和陸地為簡單運(yùn)動。由上往下依次為:

  1. [數(shù)字:0] 
  2.  
  3. [標(biāo)志:Get Ready!] 
  4.  
  5. [圖標(biāo):操作方法] 
  6.  
  7. [鳥:上下飛行] 
  8.  
  9. [陸地:向左移動] 
  10.  
  11. [背景:隨機(jī)晝夜] 

2、  游戲進(jìn)行態(tài):當(dāng)點(diǎn)擊一下屏幕,鳥、柱子被解封,陸地依然保持原來運(yùn)動狀態(tài),背景不變,這里采用相對運(yùn)動效果,其實(shí)背景是沒有運(yùn)動的,而鳥也只是上下運(yùn)動,根本就沒有向前飛一點(diǎn)!

  1. [鳥:向上躍起,然后以豎直上拋的邏輯使鳥運(yùn)動;同時,還要專門為鳥的姿態(tài)設(shè)計合理的旋轉(zhuǎn)函數(shù)] 
  2.  
  3. [柱子:向柱子鏈表里加入新的柱子,并使鏈表里的所有柱子開始向左移動,當(dāng)柱子完全超出最左邊界時,將該柱子刪除;同樣的,當(dāng)最后一個柱子到達(dá)某一特定距離時,向鏈表里加入一個新的柱子,這樣既保證了剛開始的柱子出現(xiàn)效果的真實(shí)、有趣性,又保證了資源的合理回收,提高算法高效性] 
  4.  
  5. [分?jǐn)?shù):當(dāng)柱子到達(dá)鳥所在的位置時就要進(jìn)行碰撞檢測,如果沒有碰撞且鳥跨過柱子,就讓分?jǐn)?shù)+1,并響鈴] 
  6.  
  7. [陸地:保持勻速運(yùn)動邏輯,采用循環(huán)貼圖技術(shù),產(chǎn)生無縫效果] 

3、  死亡狀態(tài):鳥的死亡狀態(tài)看似簡單,但是仔細(xì)分析并非如此。各種細(xì)節(jié)都要分別考慮:

  1. [直接撞地態(tài):中止所有運(yùn)動邏輯,同時留一定的時間間隔,產(chǎn)生畫面轉(zhuǎn)換的質(zhì)感] 
  2.  
  3. [高撞柱子態(tài):旋轉(zhuǎn)為垂直態(tài),然后自由落體;撞擊時發(fā)出聲音,然后發(fā)出墜落的聲音,同時進(jìn)行碰撞檢測,碰到陸地中止一切運(yùn)動,進(jìn)行時間停留] 
  4.  
  5. [低撞柱子態(tài):和高撞柱子態(tài)的區(qū)別是,墜落的時間少了,音樂沒有完頁面就跳轉(zhuǎn)了,所以要控制時間停留長度,產(chǎn)生高仿的效果] 

4、  死亡之后態(tài):鳥撞地之后要有一定的時間逗留防止頁面跳轉(zhuǎn)過快不舒服的感覺。接下來首先貼上game_over的圖標(biāo),然后計分板從下往上飛來,接著開始計分并張貼是否為新紀(jì)錄和是否獲得金牌之類的,最后貼上兩個按鈕等待響應(yīng)。

  1. [陸地:停止運(yùn)動] 
  2.  
  3. [圖標(biāo):展示Game_Over] 
  4.  
  5. [計分板:動畫效果,從下往上飛來并帶有音效,當(dāng)飛到指定位置時開始從0累計得分,并統(tǒng)計是否為新紀(jì)錄和是否獲得相應(yīng)的獎牌] 
  6.  
  7. [按鈕:靜態(tài)貼圖,但是相應(yīng)的時候有上下振動的效果] 

#p#

六、經(jīng)典算法說明:

1、 ON_WM_TIMER:時間消息映射:

主要控制全局邏輯運(yùn)算的時間進(jìn)程,根據(jù)當(dāng)前的狀態(tài)做相應(yīng)的邏輯運(yùn)算;同時邏輯運(yùn)算也會對全局的游戲狀態(tài)進(jìn)行改變,實(shí)現(xiàn)全局操控邏輯實(shí)現(xiàn):(與此相同的draw函數(shù)這里就不再詳細(xì)介紹)

  1. void CMainWindow::OnTimer(UINT nTimerID){ 
  2.     switch(nTimerID){ 
  3.     case bird_time: 
  4.         if(game_state==before_game)bird.logic(before_game,game_state);//開始前 
  5.         break
  6.     case land_time: 
  7.         if(game_state==before_game){//開始前 
  8.             land.logic();//路 
  9.         }else if(game_state==during_game){//游戲中 
  10.             if(bird.state!=bird_delay)land.logic();//路 
  11.             bird.logic(1,game_state);//鳥正常運(yùn)動 
  12.             if(bird.state!=bird_delay)pipe.logic(goals,bird,game_state);//管道 
  13.         }else if(game_state==dying_game){//失敗中 
  14.             bird.logic(2,game_state);//垂直下落 
  15.         }else if(game_state==end_game){//顯示game-over+計分板+2個按鈕 
  16.             if(panel.state==finish)button.logic(game_state); 
  17.             if(last_state>=10)panel.logic(goals,best_goals); 
  18.         }else if(game_state==start_game){//重新開始 
  19.             restart(); 
  20.             game_state=before_game; 
  21.         } 
  22.         break
  23.     default:break
  24.     } 
  25.     draw(); 

2、 ON_WM_LEFTBUTTONDOWN:鼠標(biāo)左鍵按下監(jiān)聽映射:

每次單擊鼠標(biāo)左鍵相應(yīng)該函數(shù),然后該函數(shù)根據(jù)不同的游戲狀態(tài)做出不同的邏輯操作:①、[當(dāng)游戲處于0態(tài),即:游戲開始之前時,點(diǎn)擊鼠標(biāo),狀態(tài)改為1態(tài),柱子加入開始移動,鳥躍起開始飛翔][當(dāng)處于游戲態(tài)時:每次點(diǎn)擊鳥都會躍起];②、[當(dāng)處于結(jié)束態(tài)時:按鈕等待鼠標(biāo)按動,并根據(jù)區(qū)域做出判斷是否按了按鈕,按了哪一個]

  1. void CMainWindow::OnLButtonDown(UINT nFlags, CPoint point){ 
  2.     if(game_state==0){ 
  3.         game_state=1; 
  4.         pipe.add(); 
  5.         bird.jump(); 
  6.     }else if(game_state==1){ 
  7.         bird.jump(); 
  8.     }else if(game_state==3){ 
  9.         button.click(point); 
  10.     } 

3、PipeList::logic柱子邏輯函數(shù),包括碰撞檢測!

為了簡化起見,我把音頻播放的部分刪去了:這里是遍歷整個鏈表,對于每一個柱子,由上到下每一個if為:①、[判斷鳥是否正好穿越一個柱子,如果是則分?jǐn)?shù)加1];②、[判斷柱子是否出界,超出就不把該柱子放回鏈表,相當(dāng)于刪除];③、[鳥與地面的碰撞檢測];④、[鳥與柱子的碰撞檢測]⑤、[最后一個if是判斷最后一個柱子是否到達(dá)指定位置,如果到達(dá)就向鏈表尾部加入一個新的柱子,從而保證了柱子連續(xù)且間距統(tǒng)一]

  1. //--------------------------------------------------------------- 
  2. void PipeList::logic(int &goals,Bird &bird,int &game_state){//邏輯函數(shù) 
  3.     int count=pipe.GetCount(); 
  4.     for(int i=0;i<count;i++){ 
  5.         Pipe temp=pipe.GetHead(); 
  6.         pipe.RemoveHead(); 
  7.         temp.logic(); 
  8.         if(temp.pos_x==64){ 
  9.             goals+=1; 
  10.         } 
  11.         if(temp.pos_x>=-70)pipe.AddTail(temp); 
  12.         //碰撞檢測 
  13.         if(23+bird.y+48-$d>400){//與地面 
  14.             bird.y=400-230-48+$d; 
  15.             bird.stop(); 
  16.             game_state=2; 
  17.         }else if(!(65+48-$d < temp.pos_x || temp.pos_x+52<65+$d)){//與柱子 
  18.             if(!(230+bird.y+$d > temp.pos_y+320 && temp.pos_y+420 > 230+bird.y+48-$d)){ 
  19.                 game_state=2;//表示碰撞,游戲結(jié)束; 
  20.             } 
  21.         } 
  22.     } 
  23.     if((pipe.GetTail()).pos_x<=140){ 
  24.         Pipe temp; 
  25.         pipe.AddTail(temp); 
  26.     } 
  27. }//--------------------------------------------------------------- 

4、 Bird::logic鳥的運(yùn)動邏輯,包括所有運(yùn)動狀態(tài)(絕密算法?。。。?/strong>

同樣的為了簡單我也把音頻部分的代碼刪去了。此函數(shù)是分別將鳥的運(yùn)動的各個狀態(tài)做分別處理:①、[開始前:采用正弦函數(shù)波動飛行同時改變翅膀狀態(tài)];②、[正常飛行時:又把鳥的運(yùn)動狀態(tài)劃分為向上、向下、旋轉(zhuǎn)、停留四個狀態(tài)分別處理];③、[下落死亡狀態(tài):這里用了一個輔助時間變量,控制幀動畫播放]

  1. //--------------------------------------------------------------- 
  2. void Bird::logic(int ID,int &game_state){ 
  3.     if(ID==0){//開始前 
  4.         y=4*sin(Time*PI); 
  5.         Time+=0.25; 
  6.         fly_state=(fly_state+1)%3; 
  7.     }else if(ID==1){//正常 
  8.         switch(state){ 
  9.         case state_up: 
  10.             v+=a; 
  11.             y+=v; 
  12.             dis_state--; 
  13.             if(dis_state==0){ 
  14.                 state=state_turn; 
  15.                 Time=0; 
  16.             } 
  17.             break
  18.         case state_turn: 
  19.             v+=a; 
  20.             y+=v; 
  21.             if(230+y+48-$d>=400){ 
  22.                 y=400-230-48+$d; 
  23.                 stop(); 
  24.                 game_state=3; 
  25.             } 
  26.             dis_state++; 
  27.             if(dis_state==1 && Time<=0.4){ 
  28.                 Time+=0.1; 
  29.                 dis_state=0; 
  30.             } 
  31.             if(dis_state==6){ 
  32.                 state=state_down; 
  33.             } 
  34.             break
  35.         case state_down: 
  36.             v+=a; 
  37.             y+=v; 
  38.             if(delay==0 && 230+y+48-$d>=400){ 
  39.                 y=400-230-48+$d; 
  40.                 stop(); 
  41.                 state=state_delay; 
  42.             } 
  43.             break
  44.         case state_delay: 
  45.             delay++; 
  46.             if(delay==8){game_state=3;} 
  47.             break
  48.         default:break
  49.         } 
  50.         if(dis_state!=6)fly_state=(fly_state+1)%3; 
  51.     }else if(ID==2){//下落 
  52.         delay++; 
  53.         if(delay==8){//撞擊聲延時 
  54.         } 
  55.         if(delay<60){//下落運(yùn)算 
  56.             y+=v; 
  57.             v+=a; 
  58.             if(dis_state!=6)dis_state++; 
  59.             if(230+y+48-$d>=400){//撞地檢測 
  60.                 y=400-230-48+$d; 
  61.                 stop(); 
  62.                 if(dis_state==6){delay=60;} 
  63.             } 
  64.         }else if(delay==66){//墜地后延時 
  65.             game_state=3; 
  66.         } 
  67.     } 
  68. }//--------------------------------------------------------------- 

5、Button::按鈕識別和按鈕動畫邏輯實(shí)現(xiàn):

通過鼠標(biāo)所在的點(diǎn)判斷是否在按鈕所在的矩形區(qū)域內(nèi)來判斷是否點(diǎn)了該按鈕:

  1. //--------------------------------------------------------------- 
  2. void Button::click(CPoint &point){ 
  3.     if(point.x>=25 && point.x<=25+116 && point.y>=340 && point.y<=340+70){ 
  4.         kind=play; 
  5.         move=true
  6.     }else if(point.x>=155 && point.x<=155+116 && point.y>=340 && point.y<=340+70){ 
  7.         kind=score; 
  8.         move=true
  9.         LoadFromResource(IDR_HTML1); 
  10.     }else kind=none; 
  11. }//--------------------------------------------------------------- 
  12. //這里主要解決顫動效果實(shí)現(xiàn)及按鈕狀態(tài)復(fù)原: 
  13. //--------------------------------------------------------------- 
  14. void Button::logic(int &game_state){ 
  15.     if(kind==play){//顫動控制 
  16.         if(move==true){ 
  17.             play_y=2; 
  18.             move=false
  19.         }else
  20.             play_y=0; 
  21.             kind=none; 
  22.             game_state=4; 
  23.         } 
  24.     }else if(kind==score){ 
  25.         if(move==true){ 
  26.             score_y=2; 
  27.             move=false
  28.         }else
  29.             score_y=0; 
  30.             kind=none; 
  31.         } 
  32.     } 
  33. }//--------------------------------------------------------------- 

七、重量級問題解決:

1、 飛翔弧度、旋轉(zhuǎn)狀態(tài)難題:

正如前面的鳥的飛翔邏輯代碼所示:鳥的飛翔過程并不是簡單的自由上拋就能解決的;我通過大量實(shí)驗(yàn)發(fā)現(xiàn)必須把這個過程分為上面介紹的4步,然后每一步用更加詳細(xì)的數(shù)學(xué)公式計算鳥的運(yùn)行邏輯[因?yàn)榇颂幬覀儽仨毧紤]鳥的旋轉(zhuǎn)效果和鳥的速度同步,所以這才是難點(diǎn)所在]。因?yàn)樯厦嬉呀?jīng)詳細(xì)說明了,這里就不再重復(fù),但這是一大難點(diǎn)!

2、 混音效果、完美封裝處理:

本來音樂播放只要用PlaySound函數(shù)一句話就能產(chǎn)生音樂播放效果,但是當(dāng)全部節(jié)點(diǎn)都放好音樂時,發(fā)現(xiàn)當(dāng)鳥正好越過柱子發(fā)出加分的鈴聲時和鳥飛翔的聲音無法混合播放,而是出現(xiàn)了嚴(yán)重的打斷效果!導(dǎo)致聽起來很不舒服。難道只有重新用Direct-X來處理混音嗎?想想就冒汗….畢竟游戲已經(jīng)接近尾聲了,沒必要再推翻MFC框架而用Direct-X來吧!于是發(fā)現(xiàn)用用2個不同的函數(shù)可以解決這個問題,即:其他部分不變還是用PlaySound函數(shù),而分?jǐn)?shù)增加的音樂用mciSendString函數(shù)來播放可以解決問題。

但是mciSendString只能加在特定路徑下的音頻,無法處理資源文件下的wav文件,這該怎么辦呢?難道要放棄資源的全封裝效果?那多不好,于是還是被我解決了!我采用的思路是:把資源文件讀到一個中間虛擬文件,然后把該中間文件加載金mciSendString就可以啦!下面是如何讀取資源文件并轉(zhuǎn)為中間文件的函數(shù):

注:PlaySound(MAKEINTRESOURCE(ID),AfxGetResourceHandle(),SND_RESOURCE|SND_ASYNC);

  1. //--------------------------------------------------------------- 
  2. bool ExtractResource(LPCTSTR strDstFile, LPCTSTR strResType, LPCTSTR strResName) 
  3.     // 創(chuàng)建文件 
  4.     HANDLE hFile = ::CreateFile(strDstFile, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL); 
  5.     if (hFile == INVALID_HANDLE_VALUE) 
  6.         return false
  7.  
  8.     // 查找資源文件中、加載資源到內(nèi)存、得到資源大小 
  9.     HRSRC    hRes    = ::FindResource(NULL, strResName, strResType); 
  10.     HGLOBAL    hMem    = ::LoadResource(NULL, hRes); 
  11.     DWORD    dwSize    = ::SizeofResource(NULL, hRes); 
  12.      
  13.     // 寫入文件 
  14.     DWORD dwWrite = 0;      // 返回寫入字節(jié) 
  15.     ::WriteFile(hFile, hMem, dwSize, &dwWrite, NULL); 
  16.     ::CloseHandle(hFile); 
  17.  
  18.     return true
  19. }//-------------------------------------------------------------- 

3、 創(chuàng)建分享、窗口截屏技術(shù):

其實(shí)已經(jīng)解決上面幾個問題已經(jīng)仿的差不多啦,但是還不完美!于是開始著手解決那個分享按鈕[要知道這對MFC來說難度不亞于不用引擎來做圖像處理!]可是這并不代表問題不可解。先不說,先看看效果!

知道難度了吧!這是分享按鈕自動創(chuàng)建的網(wǎng)頁,然后還有圖片信息,下載鏈接[這樣才會吸引更多的人玩]由于這里涉及到非基礎(chǔ)MFC知識,這里只提示一下:用到的技術(shù)是HTML+JS技術(shù)[也就是網(wǎng)頁編程+腳本設(shè)計]

八、開發(fā)感想: 

實(shí)踐出真知,通過開發(fā)這款簡單的像素游戲,遇到了很多問題,也學(xué)到了很多,如今將近一年后拿出來還覺得當(dāng)時做的這個是一個小奇跡~雖然這一年里也做了不少好玩的軟件、神奇的硬件、以及一些軟硬結(jié)合的小東西,但是都沒有這個讓人感覺充實(shí)。仔細(xì)想想,我覺得之所以它能讓開發(fā)它的人如此留念,很大一部分原因是因?yàn)閷λ姆磸?fù)斟酌修改與追求完美的過程中所積淀的解決問題、享受成果的樂趣吧!如今大三上也快GAME OVER了。這一年可能太過于浮躁,一方面想施展下身手、另一方面又技藝不精,會的挺多但都淺嘗輒止,好的想法要很長時間才能實(shí)現(xiàn),遇到優(yōu)化又不能靜下心來,整天忙忙碌碌基本1~2點(diǎn)休息,可是很少出這種精致的作品~時間很快,暑假實(shí)習(xí)過后留在大學(xué)里的日子就不多啦,且行且珍惜~

博主主頁:http://www.cnblogs.com/zjutlitao/

上述工程資料:http://pan.baidu.com/s/18i2dS

責(zé)任編輯:張偉 來源: 博客園
相關(guān)推薦

2023-07-19 21:48:45

2009-07-13 08:49:54

Ubuntu桌面版Linux

2009-07-14 09:02:30

Ubuntu開源操作系統(tǒng)Linux

2009-05-13 08:35:21

2009-10-29 08:29:09

Ubuntu 9.10

2019-10-09 09:25:08

谷歌編程開發(fā)者

2021-05-15 08:56:00

Chrome瀏覽器往返緩存

2016-03-21 14:47:45

微軟桌面版Office 2

2014-02-12 17:31:17

Flappy Bird

2009-12-23 13:53:54

Linux桌面版

2009-10-15 09:49:10

2021-08-02 10:09:15

Chrome桌面版截圖功能

2013-11-25 16:36:06

Linux企業(yè)級桌面版Ubuntu

2021-02-02 06:29:52

Windows10操作系統(tǒng)騰訊 QQ

2011-08-16 23:06:28

firefox6移動版桌面版

2021-04-29 05:48:59

微軟Office 桌面應(yīng)用

2009-03-27 17:56:59

Linux紅帽CEO桌面版

2022-01-04 12:51:40

Ubuntu服務(wù)器桌面版

2009-04-04 09:31:34

Windows 7微軟操作系統(tǒng)

2009-04-07 08:49:46

微軟Windows 7操作系統(tǒng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號