C/C++製作益智遊戲:2048(源碼詳解)

前言

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截圖系統、編寫雷霆戰機等經典遊戲的免費知識分享課。

如果你對程序員這份工作滿懷熱愛,如果你樂意走在技術的最前沿,不妨加入我們,將所有的迷惘一掃而光吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章