两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

一、項(xiàng)目介紹

這是一個(gè)可以單人進(jìn)行的俄羅斯方塊小游戲。

按左右鍵移動(dòng)方塊,按上鍵可以旋轉(zhuǎn)方塊,按下鍵可以加速方塊的下落(需要控制好按下的時(shí)長(zhǎng),否則下一個(gè)方塊也會(huì)加速落下)。方塊碰到屏幕底部,或者碰到已經(jīng)堆積的方塊就會(huì)停下,此時(shí)上方會(huì)落下下一個(gè)方塊。右側(cè)會(huì)對(duì)下一個(gè)方塊的種類進(jìn)行提示。

 編譯環(huán)境:visual c++ 6.0

第三方庫(kù):Easyx2022  注意需要提前安裝easyX,如沒(méi)有基礎(chǔ)可以先了解easyX圖形編程


二、運(yùn)行截圖

俄羅斯方塊1


俄羅斯方塊2


三、源碼解析

游戲邏輯:

1.     生成界面,初始化程序

2.     游戲開(kāi)始循環(huán)。每次循環(huán)檢測(cè)輸入按鍵做出反應(yīng),之后睡眠50毫秒,再開(kāi)始下一次循環(huán)。

3.     按住上鍵調(diào)用旋轉(zhuǎn)的函數(shù)。

4.     按住左右鍵,改變方塊的橫坐標(biāo),調(diào)用對(duì)應(yīng)函數(shù)。

5.     Esc 鍵退出程序。

6.     在循環(huán)當(dāng)中,利用計(jì)時(shí)器判斷是否過(guò)了500毫秒,如果過(guò)了則下落一格。下落一格則檢測(cè)底部是否碰撞,碰撞則重新生成方塊,改變對(duì)下一個(gè)方塊的提示,清除連成一行的方塊并得分,檢測(cè)游戲是否結(jié)束。

7.     檢測(cè)是否按住下鍵,按住則加速下落。

8.     失敗后循環(huán)結(jié)束,退出游戲。

 

根據(jù)這些我們需要完成的功能,我們定義兩個(gè)類。其一為游戲類,內(nèi)置地圖,分?jǐn)?shù),時(shí)間等整局游戲的變量,以及設(shè)置地圖,判讀滿行,清除行等操作函數(shù)。

另一個(gè)類是方塊類,設(shè)置方塊的坐標(biāo),類型,旋轉(zhuǎn)方向,顏色等特征,以及對(duì)應(yīng)的初始化,添加,移動(dòng),旋轉(zhuǎn)等操作函數(shù)。


接下來(lái)是相關(guān)步驟的詳細(xì)解析。

  1. 界面生成以及初始化

SetWindowText(initgraph(350, 440), "俄羅斯方塊dotcpp.com");
 
         // 設(shè)置繪圖顏色
         setbkcolor(WHITE);
         cleardevice();
         setlinecolor(BLACK);
 
         // 生成游戲界面和數(shù)據(jù)
         srand(time(NULL));
         Block::generateBlockData();
 
         Game game;
         game.drawMap();
         game.drawPrompt();
 
         Block b(game);
         Block nextBlock(game, 11, 2); // 下一方塊
         clock_t start = 0;                                  // 時(shí)鐘開(kāi)始時(shí)間
         clock_t end;                                          // 時(shí)鐘結(jié)束時(shí)間
 
         ExMessage msg;
 
         nextBlock.draw();

這里用到了一些Easyx當(dāng)中的函數(shù)。如無(wú)注明,后文中非本程序定義的函數(shù)也都位于Easyx當(dāng)中。
setbkcolor()用于設(shè)置當(dāng)前設(shè)備繪圖背景色。
Cleardevice()使用當(dāng)前背景色清空繪圖設(shè)備.
Setlinecolor()用于設(shè)置當(dāng)前設(shè)備畫(huà)線顏色。
ExMessage結(jié)構(gòu)體用于保存鼠標(biāo)信息。
在此處我們還定義了幾個(gè)相關(guān)的函數(shù)。
 
Block::generateBlockData()用于設(shè)定不同種類方塊的信息。blockData是一個(gè)三維數(shù)組,用于保存所有方塊的數(shù)據(jù),第一位是方塊種類,二三位則是橫縱坐標(biāo),調(diào)節(jié)這些數(shù)據(jù)與游戲內(nèi)容一致。

roundrect用于畫(huà)無(wú)填充的圓角矩形。

rectangle用于畫(huà)無(wú)填充的矩形。

setfillcolor用于設(shè)置當(dāng)前設(shè)備填充顏色。

fillrectangle用于畫(huà)有邊框的填充矩形。

game.drawPrompt()用于繪制提示界面,主要是各種提示。

其中最主要用到的outtextxy是在x,y坐標(biāo)處輸出文字。

其余的還有settextstyle設(shè)置當(dāng)前文字樣式。

gettextstyle獲取當(dāng)前文字樣式。

settextcolor設(shè)置當(dāng)前文字顏色。

Block::draw()用來(lái)繪制方塊。

還是用到了setfillcolor和fillrectangle,根據(jù)方塊數(shù)據(jù)對(duì)應(yīng)的xy坐標(biāo),用雙層循環(huán)的方式輸出結(jié)果。注意在Y坐標(biāo)為負(fù)時(shí)不繪制。

 

2. 游戲循環(huán)

while (true)
         {
                   b.clear();
                   clearrectangle(20, 20, 220, 420);
                   game.drawMap();
        ……
           b.draw();
              game.clearLine();
              FlushBatchDraw();      // 刷新緩沖區(qū)
              Sleep(50);                   // 每 50 毫秒接收一次按鍵
       }

b是Block類的一個(gè)對(duì)象。

clearrectangle用于清空矩形區(qū)域。

FlushBatchDraw用于執(zhí)行未完成的繪制任務(wù)。

其中也用到了Block類中定義的兩個(gè)函數(shù)Block::draw和Block::clear。前者已經(jīng)在前文中提到過(guò),而后者則是把繪制函數(shù)換成了clearrectangle,以此來(lái)清除繪制的方塊。通過(guò)調(diào)用clear再調(diào)用draw,可以及時(shí)地顯示出方塊的變化。

在之后還調(diào)用了Game::clearLine()這個(gè)函數(shù)。其目的是判斷哪一行已經(jīng)滿了,并將其清除以及增加得分。

void Game::clearLine()
{
       int line = -1;
       // 判斷哪一行滿行
       for (int j = 0; j < MAP_HEIGHT; j++)
       {
              if (checkLine(j))
              {
                     line = j;
                     break;
              }
       }
 
       if (line != -1)
       {
              // 將上一行移至滿行
              for (int j = line; j > 0; j--)
              {
                     for (int i = 0; i < MAP_WIDTH; i++)
                     {
                            map[i][j] = map[i][j - 1];
                     }
              }
              score += 10; // 將游戲分?jǐn)?shù)加 10
       }
       drawPrompt();
}

首先用循環(huán)判定哪一行是滿的,其中用到了Game::checkLine(),其內(nèi)部也是一個(gè)循環(huán),依次檢測(cè)某一y坐標(biāo)對(duì)應(yīng)的所有x坐標(biāo)是否都為1。如果檢測(cè)到某行是滿的,跳出循環(huán),繼續(xù)函數(shù)的后續(xù)部分。不用擔(dān)心沒(méi)有判斷所有行是否填滿,因?yàn)樵?0毫秒之后,該函數(shù)會(huì)再次被調(diào)用。

然后,將被消除那一行上方的所有行都向下移動(dòng)一行。循環(huán)從j行開(kāi)始,以y坐標(biāo)遞減的方式執(zhí)行,讓map變量(所有方塊的位置)對(duì)應(yīng)坐標(biāo)位置的數(shù)據(jù)等于其y坐標(biāo)減一的數(shù)據(jù)。最后如果消除,則將游戲分?jǐn)?shù)加10。調(diào)用繪制提示界面的函數(shù)drawPrompt(),將得分顯示在旁邊。

 

3.    按下上鍵

這里先看我們?nèi)绾潍@取鍵盤信息。

while (peekmessage(&msg, EM_KEY) && msg.message == WM_KEYDOWN)

              {

                     switch (msg.vkcode)

                     {

peekmessage用于獲取一個(gè)消息,并立即返回。其中參數(shù)&msg表示用指針的形式保存獲取到的信息,而 EM_KEY意味這是鍵盤信息。這個(gè)函數(shù)獲取消息的返回值為True,如果沒(méi)有獲取到,則返回False。

右邊的msg為ExMessage結(jié)構(gòu)體的對(duì)象,msg.message == WM_KEYDOWN表明獲取到的信息為鍵盤按下。上面的代碼意味著,如果你向程序發(fā)出了指令,并且該指令是鍵盤按下時(shí),循環(huán)才會(huì)執(zhí)行。

msg.vkcode代表按鍵的虛擬鍵碼。很顯然,

case 'W':

                     case VK_UP:

                            b.rotate();

                            break;

意味著如果你按下上鍵或者W鍵,才會(huì)執(zhí)行b.rotate()。

b.rotate()用于改變b(Block)類型的數(shù)據(jù)。執(zhí)行會(huì)改變其中block[4][4]這個(gè)二維數(shù)組,這個(gè)數(shù)組用1,0來(lái)表示在對(duì)應(yīng)位置是否存在方塊。對(duì)每種情況分類討論,得出旋轉(zhuǎn)之后的結(jié)果。

 

4.按下左右鍵,方塊左右移動(dòng)

                            // 左鍵移動(dòng)

                     case 'A':

                     case VK_LEFT:

                            b.move(1);

                            break;

 

                            // 右鍵移動(dòng)

                     case 'D':

                     case VK_RIGHT:

                            b.move(2);

                            break;

在Block類中,我們定義了move函數(shù)。其中只有一個(gè)參數(shù),0 表示下移一格,1 表示左移一格,2 表示右移一格,當(dāng)下移檢測(cè)到碰撞時(shí)返回 true。

switch (direction)

       {

       case 0:

              y++;

              if (checkCollision())

              {

                     y--;

                     return true;

              }

              break;

其邏輯很簡(jiǎn)單,就是根據(jù)輸入的不同情況,改變x或者y的坐標(biāo)(x,y是整個(gè)大方塊的坐標(biāo))。之后進(jìn)行碰撞檢測(cè),如果碰撞,取消移動(dòng)。上面是其中下方碰撞情況,注意如果是向左或向右移動(dòng),則需要返回False,因?yàn)榉祷豑rue時(shí),方塊便落到地圖上了。

Block::checkCollision()用于碰撞檢測(cè)。
bool Block::checkCollision() const
{
       for (int i = 0; i < 4; i++)
       {
              for (int j = 0; j < 4; j++)
              {
                     // 判斷方塊是否與地圖發(fā)生碰撞,頂部不判斷
                     if ((game.getMap(x + i, y + j) || 20 + BLOCK_WIDTH * (x + i) < 20 || 20 + BLOCK_WIDTH * (x + i) + BLOCK_WIDTH > 220 || 20 + BLOCK_WIDTH * (j + y) + BLOCK_WIDTH > 420) && block[i][j])
                     {
                            return true;
                     }
              }
       }
       return false;
}

用雙重循環(huán),判定每一個(gè)小方塊是否超出地圖邊界,或者與地圖上方塊重疊。

 


四、完整源碼

俄羅斯方塊C++完整源碼(easyX版)

點(diǎn)贊(0)

C語(yǔ)言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競(jìng)賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:

一點(diǎn)編程也不會(huì)寫(xiě)的:零基礎(chǔ)C語(yǔ)言學(xué)練課程

解決困擾你多年的C語(yǔ)言疑難雜癥特性的C語(yǔ)言進(jìn)階課程

從零到寫(xiě)出一個(gè)爬蟲(chóng)的Python編程課程

只會(huì)語(yǔ)法寫(xiě)不出代碼?手把手帶你寫(xiě)100個(gè)編程真題的編程百練課程

信息學(xué)奧賽或C++選手的 必學(xué)C++課程

藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競(jìng)賽課入門課程

手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程

Dotcpp在線編譯      (登錄可減少運(yùn)行等待時(shí)間)