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

一、項目介紹

這是一個可以單人進(jìn)行的2048小游戲。

游戲的目的是逐漸增大界面上的數(shù)字,獲取更高的分?jǐn)?shù),直至有數(shù)字達(dá)到2048.游戲用方向鍵控制(或者是wasd),每當(dāng)你按下方向鍵,所有的數(shù)字都會向那個方向運動到頭,如果有兩個相同的數(shù)字碰撞在一起,則會產(chǎn)生一個2倍的數(shù)字。

 

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

第三方庫:Easyx2022

 

二、運行截圖

2048游戲12048游戲2

2048游戲32048游戲4

 

三、源碼解析

我們先來思考一下游戲的邏輯。

在經(jīng)過了初始化以及界面生成之后,玩家其實只需要做出很簡單的輸入,就可以推進(jìn)游戲的進(jìn)程,無非就按下方向鍵,界面做出反應(yīng),然后接收下一次指令……這樣,整體邏輯就已經(jīng)很清晰了。

初始化;

繪制界面;

玩家操作,界面及數(shù)據(jù)變化,檢測是否勝利,若非勝利,循環(huán)操作步驟。

下面是主函數(shù):

int main()
{
       bool ctn = true;                                 // 該值代表是否重開新局
       SetWindowText(initgraph(350, 440), "2048-dotcpp.com");                       // 初始化圖形界面
       srand((unsigned)time(NULL));
       while (ctn)
       {
              init();                                                // 新的一局,程序初始化
              drawmap();                                      // 繪制界面
              int endmode = 0;                       // 結(jié)束方式,1 代表勝利,2 代表失敗
              while (1)
              {
                     move();                                     // 玩家操作
                     drawmap();                               // 繪制界面
                     if (win())                             // 勝利
                     {
                            endmode = 1;
                            break;
                     }
                     if (gameover())                         // 失敗
                     {
                            endmode = 2;
                            break;
                     }
              }
              int t;                                          // 獲取用戶選擇的按鈕
              if (endmode == 1)                     // 勝利
                     t = MessageBox(0, _T("You win!\n再來一局?"), _T("繼續(xù)"), MB_OKCANCEL);
              if (endmode == 2)                     // 失敗
                     t = MessageBox(0, _T("Game over!\n再來一局?"), _T("繼續(xù)"), MB_OKCANCEL);
              if (t == IDCANCEL)ctn = false;  // 若用戶選擇 取消,則不重新開局
       }
       closegraph();                                   // 關(guān)閉圖形界面
       return 0;
}

Initgraph用于初始化圖形窗口,參數(shù)為窗口大小。在頭文件easyx中引入。

接著構(gòu)建循環(huán),在需要時重復(fù)一局游戲。

初始化,然后不斷接收用戶的輸入。

最后用MessageBox輸出文字。MessageBox是Windows.h當(dāng)中的內(nèi)容,用于彈出對話框。

還要說明的一點是_T()這個函數(shù)。_T()是一個宏,他的作用是讓程序支持Unicode編碼,用來保證兼容性。VC支持ascii和unicode兩種字符類型,用_T可以保證從ascii編碼類型轉(zhuǎn)換到unicode編碼類型的時候,程序不需要修改。

 

接下來看需要定義的函數(shù)。

viod init()//初始化函數(shù)

void drawmap()// 定義繪制界面

void move()// 定義玩家操作

bool gameover()// 判斷游戲結(jié)束

bool win()// 判斷勝利

還有變量:

const COLORREF BGC = RGB(250, 248, 239);// 定義背景色常量

int score, best, a[5][5], b[5][5];// score 為本局分?jǐn)?shù),best為當(dāng)前最佳紀(jì)錄,a數(shù)組為棋盤,b數(shù)組為a的備份

bool mov[5][5];// 棋盤上的點是否已被移動過(避免重復(fù)移動)

可以用二維數(shù)組來存儲游戲的數(shù)據(jù)。

 

然后是每個函數(shù)的實現(xiàn)過程。

初始化:

void init()
{
       setbkcolor(BGC);
       setbkmode(TRANSPARENT);
       score = 0;
       memset(a, 0, sizeof(a));
       int x1 = rand() % 4 + 1, y1 = rand() % 4 + 1, x2 = rand() % 4 + 1, y2 = rand() % 4 + 1;  // 隨機(jī)生成兩個初始點
       a[x1][y1] = a[x2][y2] = 2;                          // 初始點初始化為 2
}
setbkcolor用于設(shè)置當(dāng)前設(shè)備繪圖背景色。
setbkmode用于設(shè)置當(dāng)前設(shè)備圖案填充和文字輸出時的背景模式,TRANSPARENT意味著背景色是透明的。
在游戲開始時,要將兩個點的值設(shè)為2。
 
繪制界面:
void drawmap()
{
       // 開始批量繪圖
       BeginBatchDraw();
 
       // 繪制界面主體
       cleardevice();
       settextcolor(RGB(119, 110, 101));
       settextstyle(50, 0, _T("微軟雅黑"));
       outtextxy(10, 10, "2048");
       settextstyle(20, 0, _T("微軟雅黑"), 0, 0, 550, false, false, false);
       outtextxy(10, 65, "Join the numbers and get to the 2048 tile!");
 
       setfillcolor(RGB(187, 173, 160));
 
       // 繪制當(dāng)前分?jǐn)?shù)
       solidroundrect(200, 15, 290, 60, 5, 5);
       settextcolor(RGB(230, 220, 210));
       settextstyle(15, 0, _T("微軟雅黑"), 0, 0, 600, false, false, false);
       outtextxy(230, 20, "SCORE");
       char sc[10];
       sprintf(sc, "%d", score);
       settextcolor(WHITE);
       settextstyle(25, 0, _T("微軟雅黑"), 0, 0, 600, false, false, false);
       RECT r = { 200, 30, 290, 60 };
       drawtext(sc, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
 
       // 繪制最佳紀(jì)錄
       solidroundrect(295, 15, 385, 60, 5, 5);
       settextcolor(RGB(230, 220, 210));
       settextstyle(15, 0, _T("微軟雅黑"), 0, 0, 600, false, false, false);
       outtextxy(330, 20, "BEST");
       char bs[10];
       sprintf(bs, "%d", best);
       settextcolor(WHITE);
       settextstyle(25, 0, _T("微軟雅黑"), 0, 0, 600, false, false, false);
       RECT s = { 295, 30, 385, 60 };
       drawtext(bs, &s, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
 
       // 繪制數(shù)字棋盤
       solidroundrect(10, 90, 390, 470, 5, 5);
       settextstyle(23, 0, _T("微軟雅黑"));
       settextcolor(WHITE);
       for (int i = 1; i <= 4; i++)
              for (int j = 1; j <= 4; j++)
                     if (a[i][j])               // 如果該位置沒有數(shù)字,則不繪制
                     {
                            // 用類似哈希的方法,為每個數(shù)字計算出對應(yīng)的顏色
                            setfillcolor(RGB((unsigned int)(BGC - 3 * (a[i][j] ^ 29)) % 256, (unsigned int)(BGC - 11 * (a[i][j] ^ 23)) % 256, (unsigned int)(BGC + 7 * (a[i][j] ^ 37)) % 256));
                            solidroundrect(94 * j - 80, 94 * i, 94 * j + 10, 94 * i + 90, 5, 5);
                            char num[10];
                            sprintf(num, "%d", a[i][j]);
                            RECT t = { 94 * j - 80, 94 * i, 94 * j + 10, 94 * i + 90 };
                            drawtext(num, &t, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
                     }
 
       // 結(jié)束批量繪圖
       EndBatchDraw();
}

BeginBatchDraw函數(shù)用于開始批量繪圖。執(zhí)行后,任何繪圖操作都將暫時不輸出到繪圖窗口上,直到執(zhí)行 FlushBatchDraw 或 EndBatchDraw 才將之前的繪圖輸出。

cleardevice函數(shù)使用當(dāng)前背景色清空繪圖設(shè)備。

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

settextstyle用于設(shè)置當(dāng)前字體。

outtextxy用于在指定位置繪制字符。

drawtext函數(shù)用于在指定區(qū)域內(nèi)以指定格式輸出字符串。

solidroundrect用于畫無邊框的填充圓角矩形。

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

以上的幾個函數(shù)都在easyx當(dāng)中定義。

繪制文字比較簡單,按照順序來即可;繪制棋盤則是用二重循環(huán),依次繪制出有或者無數(shù)字的區(qū)域。注意這里的顏色是以數(shù)字作為自變量算出來的。

 

然后是玩家操作部分,也是最主要的部分。

void move()// 定義玩家操作

上下左右移動的代碼比較類似,這里只放一部分即可:

memcpy(b, a, sizeof(a));                  // 將 a 備份至 b
memset(mov, false, sizeof(mov));    // 初始化 mov 為 false(所有點均未移動)
       // 獲取用戶操作
       char userkey = _getch();
       if (userkey == -32)
              userkey = -_getch();
       // 移動棋盤(移動 a 數(shù)組)
       int i,j;
       switch (userkey)
       {
       // 向上
       case 'w':
       case 'W':
       case -72:
              for (j = 1; j <= 4; j++)
                     for (i = 2; i <= 4; i++)
                     {
                            if (!a[i][j])continue;
                            int k = i;
                            while (!a[k - 1][j] && k >= 2)
                            {
                                   a[k - 1][j] = a[k][j];
                                   a[k][j] = 0;
                                   k--;
                            }
                            if (a[k][j] == a[k - 1][j] && !mov[k - 1][j])
                            {
                                   a[k - 1][j] = 2 * a[k][j];
                                   a[k][j] = 0;
                                   mov[k - 1][j] = true;
                                   score += a[k - 1][j];
                            }
                     }
              break;
     }

memcpy(b, a, sizeof(a))表示從a復(fù)制sizeof(a)個字節(jié)的內(nèi)容到b。

memset(mov, false, sizeof(mov));表示將mov中sizeof(mov)字節(jié)的內(nèi)存全部賦值為false。

這兩個函數(shù)都在string.h當(dāng)中。

_getch()用于獲取用戶鍵入的單個字符,且不需要按下回車。定義于頭文件conio.h當(dāng)中。

根據(jù)得到的這個輸入的不同,我們需要給出程序的反應(yīng)。這里以按住上鍵為例。

在按住上鍵之后,所有的數(shù)字都會向上方移動,當(dāng)然最上面一行不需要(它已經(jīng)在終點等著了)。所以我們用雙層循環(huán)從上到下遍歷二到四行的數(shù)字,執(zhí)行移動操作。沒有數(shù)字自然可以跳過,有則判斷它的上方是否為空,是則繼續(xù)移動。移動到頭后,再判斷它碰到的數(shù)字是否與它相同,是則執(zhí)行合并操作。

bool change = false;                         // 判斷經(jīng)過移動,棋盤是否改變
       // 比較當(dāng)前棋盤與移動前(b 數(shù)組)棋盤
       for (i = 1; i <= 4; i++)
              for (int j = 1; j <= 4; j++)
                     if (a[i][j] != b[i][j])
                     {
                            change = true;
                            break;
                     }
       if (!change)return;                            // 如果棋盤沒有改變,退出
       // 生成一個新數(shù)字(且不與已有數(shù)字重合)
       int x, y;
       do
       {
              x = rand() % 4 + 1;
              y = rand() % 4 + 1;
       } while (a[x][y]);
       // 有 1/6 的幾率生成數(shù)字為 4,其余情況生成數(shù)字為 2
       int n = rand() % 6;
       if (n == 5)a[x][y] = 4;
       else a[x][y] = 2;
       // 更新最佳紀(jì)錄
       best = max(best, score);
}

在執(zhí)行完移動行為之后,將棋盤與備份對照,如果沒有改變,則此次操作無效。(游戲結(jié)束會在后邊的函數(shù)當(dāng)中另行判斷)。

最后在空位生成兩個數(shù)字,更新分?jǐn)?shù)。

 

然后是檢查是否游戲結(jié)束。

bool gameover()
{
       // 對于任意一個位置,該位置為空 或 四周有位置上的數(shù)字與該位置上數(shù)字相等,說明可繼續(xù)移動(游戲可繼續(xù))
       for (int i = 1; i <= 4; i++)
              for (int j = 1; j <= 4; j++)
                     if (!a[i][j] || a[i][j] == a[i + 1][j] || a[i][j] == a[i - 1][j] || a[i][j] == a[i][j + 1] || a[i][j] == a[i][j - 1])return false;
       // 否則游戲結(jié)束
       return true;
}

簡單的雙層循環(huán)遍歷即可實現(xiàn)。

 檢查勝利的函數(shù)更為簡單。只需驗證棋盤上的數(shù)字有無達(dá)到2048就可以了。

 

四、完整源碼

 C語言生命游戲完整源碼(easyX版)

 

 


點贊(0)

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

一點編程也不會寫的:零基礎(chǔ)C語言學(xué)練課程

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

從零到寫出一個爬蟲的Python編程課程

只會語法寫不出代碼?手把手帶你寫100個編程真題的編程百練課程

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

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

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

Dotcpp在線編譯      (登錄可減少運行等待時間)