前言
C/C++作爲元老級的編程語言,任時光更迭依舊屹立不倒,哪怕如今炙手可熱的AI,其底層也是用其編寫。C/C++可以說是永不過時的語言。
那麼作爲新手該如何上手這門語言?一切不敲代碼的學編程手段都是扯淡
今天小編就推薦一個適合新手練手的C/C++項目:製作益智遊戲2048
話不多說,咱直接開始~
C/C++製作益智遊戲2048
1.編譯環境
Win10專業版x64 VS2015
2.項目運行效果
3.思路簡介:
遊戲規則:
遊戲的規則很簡單,你需要控制所有方塊向同一個方向運動,兩個相同數字的方塊撞在一起之後合併成爲他們的和,每次操作之後會在空白的方格處隨機生成一個2或者4(生成2的概率要大一些),最終得到一個“2048”的方塊就算勝利了。
2048 遊戲裏最關鍵的就是消掉方塊和在屏幕任意位置輸出數據。其中有兩個關鍵點:
一、在滿足條件情況下消除方塊
二、允許在遊戲主界面(16 宮格)中任意一格輸出數據
前者實現思路是創建一個與遊戲地圖相同維數的數組矩陣,通過數組矩陣來維護 2048 遊戲中每個格子的數據與狀態。從而玩家的移動操作都可以映射爲對數組矩陣的操作。第二點藉助 ncurses 庫可以較容易實現。
學習過程中你能學會:
- 掌握C/C++的語法、算法,Win技術。
- 學習遊戲設計與實現思路,熟悉遊戲的編寫與運行流程。
- 屏幕繪圖庫ncurses的使用,熟悉模塊與主流程的運行流程。
- 利用C/C++語法結合數據結構與算法算法處理遊戲數據。
學習成效:
學習了一個遊戲應該如何編寫與運行,學習了繪圖庫ncurses的使用,隨着我們能力的提升,可以將簡陋的 ASCII 字符換成漂亮的圖片,再加上積分牌等等。
**【文章福利】:**小編推薦自己的C語言交流羣:967051845!整理了一些個人覺得比較好的學習書籍、視頻資料共享在羣文件裏面,有需要的可以自行添加哦!~
4.主要源碼:
#include "stdafx.h"
#include <time.h>
#include <conio.h>
#define FRAMERWHIDTH 20 //一個小的格子的寬度
#define FRAMERHIGHT 20 //一個小的格子的高度
int Bound[4][4]; //抽象爲地圖
int RandNum_nFalge; //是否添加一個新的隨機數標誌 1--->產生新的隨機數 0--->不必產生新的隨機數
int Gameover_nFlage; //是否遊戲結束 1--->遊戲失敗結束 2---->遊戲勝利結束 0--->繼續正常(遊戲未結束)
int Score; //遊戲分數
//數組的移動 下標 k,j; 其中j爲k後面的第一個不爲0的數字
//左移動
void MoveLeft()
{
for (int i = 0; i < 4; i++) //一共有4行
{
for (int k = 0, j = 1; j < 4; j++) //每一行都是有4列(個數字)
{
if (Bound[i][j] > 0) //在一行中,只判k只有遇到的第一個非0的個數字 (j>0)
{
if(Bound[i][k] == Bound[i][j]) //情況一:k == j && j >0
{
Score += Bound[i][k++] *= 2;
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
else if (Bound[i][k] == 0) //情況二:k == 0 && j>0
{
Bound[i][k] = Bound[i][j];
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
else //情況三:k != j &&j >0
{
Bound[i][++k] = Bound[i][j];
if (k != j)
{
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
}
}
}
}
}
//右移動
void MoveRight()
{
for (int i = 0; i < 4; i++) //一共有4行
{
for (int k = 3, j = 2; j >= 0; j--) //每一行都是有4列(個數字)
{
if (Bound[i][j] > 0) //在一行中,只判k只有遇到的第一個非0的個數字 (j>0)
{
if (Bound[i][k] == Bound[i][j]) //情況一:k == j && j >0
{
Score += Bound[i][k--] *= 2;
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
else if (Bound[i][k] == 0) //情況二:k == 0 && j>0
{
Bound[i][k] = Bound[i][j];
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
else //情況三:k != j &&j >0
{
Bound[i][--k] = Bound[i][j];
if (k != j)
{
Bound[i][j] = 0;
RandNum_nFalge = 1;
}
}
}
}
}
}
//上移動
void MoveUp()
{
for (int i = 0; i < 4; i++) //一共有4列
{
for (int k = 0, j = 1; j < 4; j++) //每一列都是有4個數
{
if (Bound[j][i] > 0) //這個裏面j爲時刻變化的 數組行, i爲每一輪變化一次的數組的列(這裏面注意體會s數組的i和j的循環和數組裏面的區別)
{
if (Bound[j][i] == Bound[k][i]) //情況一:k == j && j >0
{
Score += Bound[k++][i] *= 2;
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
else if (Bound[k][i] == 0) //情況二:k == 0 && j>0
{
Bound[k][i] = Bound[j][i];
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
else //情況三:k != j &&j >0
{
Bound[++k][i] = Bound[j][i];
if (k != j)
{
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
}
}
}
}
}
//下移動
void MoveDown()
{
for (int i = 0; i < 4; i++) //一共有4列
{
for (int k = 3, j = 2; j >= 0; j--) //每一列都是有4個數
{
if (Bound[j][i] > 0) //這個裏面j爲時刻變化的 數組行, i爲每一輪變化一次的數組的列(這裏面注意體會s數組的i和j的循環和數組裏面的區別)
{
if (Bound[j][i] == Bound[k][i]) //情況一:k == j && j >0
{
Score += Bound[k--][i] *= 2;
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
else if (Bound[k][i] == 0) //情況二:k == 0 && j>0
{
Bound[k][i] = Bound[j][i];
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
else //情況三:k != j &&j >0
{
Bound[--k][i] = Bound[j][i];
if (k != j)
{
Bound[j][i] = 0;
RandNum_nFalge = 1;
}
}
}
}
}
}
//控制遊戲的鍵盤輸入
void KeyboardInput()
{
//char ch;
switch (_getch())
{
case 'w':
case 'W':
MoveUp();
break;
case 'a':
case 'A':
MoveLeft();
break;
case 's':
case 'S':
MoveDown();
break;
case 'd':
case 'D':
MoveRight();
break;
default:
break;
}
}
//繪畫出一行數字
void ShowNum_a_Line(int i)
{
printf_s(" ┃ ┃ ┃ ┃ ┃\n");
printf_s(" ┃");
for (int j = 0; j < 4; j++)
{
if (0 != Bound[i][j])
{
printf_s(" %5d ┃", Bound[i][j]);
}
else
{
printf_s(" ┃", Bound[i][j]);
}
}
printf_s("\n");
printf_s(" ┃ ┃ ┃ ┃ ┃\n");
}
//檢測空餘的各自的個數
int nCountNullNum()
{
int n = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (0 == Bound[i][j])
n++;
}
}
return n;
}
//生成隨機數(該函數只賦值一個空格)
void RandNum()
{
srand((unsigned int)time(NULL));
int n = rand() % nCountNullNum();
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (0 == n) //第n個爲0的個子
{
Bound[i][j] = rand() % 3 ? 2 : 4; //數組隨機生成的第n個爲0的空格子,隨機賦值的2的該路是4的2倍
goto a;
}
if (0 == Bound[i][j]) //數到第那n個位0的空格子
{
n--;
}
}
}
a:;
RandNum_nFalge = 0;
}
void ShowWindows()
{
printf_s("\n\n\n 遊戲名字:2048 分數:%-6d 開發者:詩情畫意\n", Score);
printf_s(" ------------------------------------------------------------------------------------------\n");
printf_s(" ┏━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓\n");
for (int i = 0; i < 4; i++)
{
if (i < 3)
{
ShowNum_a_Line(i);
printf_s(" ┣━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━╋━━━━━━━━━━┫\n");
}
if ( 3 == i)
{
ShowNum_a_Line(i);
printf_s(" ┗━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┻━━━━━━━━━━┛\n");
}
}
printf_s("\n\n W:↑ A:← S:↓ D:→\n");
}
//遊戲開始之前隨機初始化兩個格子
void StartDate()
{
RandNum();
RandNum();
}
//遊戲是否結束
void CheckGameOver()
{
int n1 = 0, n2 = 0;//橫着、豎着兩個兩個不相等的 次數 的計數器
for (int i = 0; i < 4; i++) //橫着橫着2個進行比較
{
for (int j = 0; j < 3; j++)
{
if (Bound[i][j] != Bound[i][j + 1])
{
n1++; //n1最多隻會比較12次
}
if (Bound[i][j] >= 2048) //單獨的一個判斷單個的Bound[][]是否大於2048,大於就說明遊戲結束(勝利)
{
Gameover_nFlage = 2;
}
}
}
for (int i = 0; i < 4; i++) //豎着豎着2個進行比較
{
for (int j = 0; j < 3; j++)
{
if (Bound[j][i] != Bound[j + 1][i])
{
n2++; //n2最多隻會比較12次
}
}
}
if (n1 == 12 && n2 == 12)
{
Gameover_nFlage = 1;//遊戲結束(遊戲失敗)
}
}
//開始遊戲循環
void StartGame()
{
system("title 2048"); //改控制檯標題名稱
system("color 0e"); //改控制檯標題背景和內容的顏色
//遊戲開始位置代碼---------------------¥¥(一局遊戲完整)
StartDate();
while (true)
{
ShowWindows();
KeyboardInput();
CheckGameOver();
if (1 == Gameover_nFlage) //判斷遊戲結束的兩種方法(Gameover_nFlage ==1 或 ==2)
{
printf_s("遊戲失敗,GAME OVER!!!\n");
}
if (2 == Gameover_nFlage)
{
printf_s("遊戲勝利,GAME SUCCESS!!!\n");
}
if (1 == RandNum_nFalge)
{
RandNum();
}
system("cls");
}
//遊戲結束位置代碼---------------------¥¥(一局遊戲完整)
}
那麼最後送給大家一個福利
一起譜寫一段關於成長的故事——
免費C/C++技術交流羣:967051845
進羣領取GDI、2048及更多項目學習資料包~
羣內不定期有Socket編程和Hook(鉤子)編程等網絡黑客技術、騰訊內部核心技術比如QQ截圖系統、編寫雷霆戰機等經典遊戲的免費知識分享課。
如果你對程序員這份工作滿懷熱愛,如果你樂意走在技術的最前沿,不妨加入我們,將所有的迷惘一掃而光吧。