一提到開發(fā)游戲,很多人都會覺得要很高深的技術,有一種望塵莫及的感覺。其實要編一款小游戲也沒有想象的那么難,下面跟著小編一起來看看C++是如何一步步制作游戲的。
本文的代碼下載地址在文章末尾,有需要的同學自取。
大家應該都玩過連連看,游戲規(guī)則不多說了,我們先看看設計思路。
第一件事要根據(jù)游戲玩法確定程序的數(shù)據(jù)結構,不同的數(shù)據(jù)結構決定了不同的算法設計,用錯了數(shù)據(jù)結構可能直接讓代碼復雜好幾倍。
連連看中玩家操作的數(shù)據(jù)是一個個的圖片,多個圖片組成一個棋盤式的矩陣界面。程序根據(jù)玩家的點擊位置計算兩個圖片的連接路線,這要求程序以最快、最簡單的方式獲得矩陣中每個格子的數(shù)據(jù)。
【源碼獲取】:
由于平臺原因,小編將完整源碼放在小編自己的C語言/C++交流④群:836880131!資料共享在群文件里面,有需要的可以自行添加獲取~
如果對代碼有任何建議,都可以添加小編的學習交流群,歡迎大家來討論~
用二維數(shù)組表示游戲中的矩陣界面比較合適,因為數(shù)組可以通過索引快速訪問數(shù)據(jù),二維數(shù)組的兩個索引剛好對應矩陣界面的(x, y)坐標。例如:
圖中矩陣數(shù)據(jù)在代碼中應該這樣表示:
data[1][2] = 0;
data[1][3] = 1;
data[2][2] = 2;
可以用不同的數(shù)字代表不同的圖片,比如:
那么上面的矩陣繪制的時候就會是這樣:
0表示空格,不顯示圖片。初始化時的空格或消除后的空格,都會被設置為0。
// 定義數(shù)組
#define WIDTH 10
#define HEIGHT 8
int data[HEIGHT][WIDTH] = { 0 };
接下來要初始化數(shù)據(jù),我打算用8種不一樣的圖片,每種6張,隨機放入矩陣中,矩陣最外一圈是空的。這個算法可以用標準庫函數(shù) std::random_shuffle 來完成。
std::random_shuffle 用于把容器內(nèi)的數(shù)據(jù)隨機打亂,因此按順序把數(shù)據(jù)放入數(shù)組中,然后調(diào)用 std::random_shuffle 就可以完成初始化。
int tmpData[HEIGHT - 2][WIDTH - 2] = { 0 }; // 定義一個8 * 6的臨時數(shù)組用于存放48個圖片數(shù)據(jù)
int picNum = 1;
int curPicCount = 0;
for (int j = 0; j < 6; ++j)
{
for (int i = 0; i < 8; ++i)
{
// 填入數(shù)據(jù)
tmpData[j][i] = picNum;
curPicCount++;
if (curPicCount == picCount)
{
picNum++; // 圖片用完,換下一種圖片
curPicCount = 0;
}
}
}
// 隨機數(shù)據(jù)
std::random_shuffle((int*)tmpData, (int*)tmpData + (HEIGHT - 2) * (WIDTH - 2));
// 再填入10*8數(shù)組中
for (size_t i = 1; i < WIDTH - 1; i++)
{
for (size_t j = 1; j < HEIGHT - 1; j++)
{
data[j][i] = tmpData[j - 1][i - 1];
}
}
斷點運行觀察數(shù)組數(shù)據(jù),和我們設計的一樣:
貼上圖片看起來還不錯:
現(xiàn)在來分析游戲玩法。
這個游戲的難點是兩個圖片連接的判定算法,要求連接線只能轉折兩次。
我的第一反應這是一個尋路算法,要求找到轉折兩次以下的最短路徑。教科書上常見的廣度優(yōu)先搜索、深度優(yōu)先搜索、DijKstra算法或是游戲中常用的A星算法,稍作修改加上兩次轉折的限制都能解決這個問題。
但是如果我用這些比較復雜的算法來教新手,顯然是在勸退。所以還是考慮找一找連線判定的算法有沒有簡單的規(guī)律。
多玩幾次游戲,把不同種類的連線記錄下來,總結后可以發(fā)現(xiàn)總共有3種連線類型,分別是不轉折連接、轉折一次和轉折兩次。
還是從最簡單的情況開始考慮。這是解決難題的通用方法:從最簡單的情況開始考慮,再逐步增加復雜的條件。
最簡單的不轉折連接,有兩種情況,橫向連線和縱向連線:
這兩種情況很容易處理,橫向、豎向依次檢查每個格子是否被阻擋即可。
// 橫向是否連接
bool IsHLinked(int x1, int y1, int x2, int y2)
{
if (y1 != y2)
{
// 橫向不在一條線
return false;
}
int minX = std::min(x1, x2); // 找到左邊的點
int maxX = std::max(x1, x2); // 找到右邊的點
for (size_t i = minX +1; i < maxX - 1; i++) // 從左到右檢查中間的點是不是空的
{
if (data[y1][i] != 0)
{
return false;
}
}
return true;
}
// 縱向是否連接
bool IsVLinked(int x1, int y1, int x2, int y2)
{
// 代碼類似
}
最后把這兩個合并就是不轉折的情況下:
// 不轉折時判斷
bool IsZeroTurnLinked(int x1, int y1, int x2, int y2)
{
if (IsHLinked(x1, y1, x2, y2))
{
return true;
}
if (IsVLinked(x1, y1, x2, y2))
{
return true;
}
return false;
}
轉折一次:
轉折一次的算法也是比較明顯的,像上圖中的兩種情況,找到綠色點的位置,如果這個點可以不轉折連到兩個紅色的圖片,那么這兩個紅色的圖片就可以通過一次轉折連接。
綠點的位置是由兩個紅點決定的,只有上圖中的兩種可能。
// 轉折一次
bool IsOneTurnLinked(int x1, int y1, int x2, int y2)
{
int tmpPointX[2] = { x1, x2 };
int tmpPointY[2] = { y2, y1 };// 找到兩個黃色點的坐標
for (size_t i = 0; i < _countof(tmpPointX); i++)
{
if (IsZeroTurnLinked(tmpPointX[i], tmpPointY[i], x1, y1)
&& IsZeroTurnLinked(tmpPointX[i], tmpPointY[i], x2, y2))
{
return true;
}
}
return false;
}
轉折兩次的情況就多了,下圖同樣是連接紅色圖片,要繞過綠色圖片。
轉折兩次的情況很多,這里無法一一列舉,但是仔細思考可以發(fā)現(xiàn)和轉折一次本質上是一樣的,就是找到兩個點,這兩個點可以分別和紅色圖片無轉折連接,并且這兩個點也可以無轉折連接。
這兩個點需要位于經(jīng)過紅色圖片的十字線上,并且只要確定一個了其中一個點,就能對應地找到另一個點:
因此只要遍歷其中一個圖片的兩條十字線經(jīng)過的所有的點,并計算出另一個圖片十字線上對應點的位置,檢查這兩個點和兩個紅色圖片是否可以無轉折連接:
bool IsTwoTurnLinked(int x1, int y1, int x2, int y2)
{
// 順著圖1的延長線縱向遍歷所有點
for (size_t j = 0; j < HEIGHT; j++)
{
int tmpX1 = x1;
int tmpY1 = j;
if (j == y1)
{
continue; // 與圖1重合
}
if (tmpX1 == x2 && tmpY1 == y2)
{
continue; // 與圖2重合
}
int tmpX2 = x2;
int tmpY2 = tmpY1; // 另一個點的坐標
if (IsZeroTurnLinked(tmpX1, tmpY1, tmpX2, tmpY2)
&& IsZeroTurnLinked(tmpX1, tmpY1, x1, y1)
&& IsZeroTurnLinked(tmpX1, tmpY1, x2, y2))
{
return true;
}
}
// 順著圖1的延長線橫向遍歷所有點
// ... 省略
return false;
}
代碼碼完了,添上圖片和鼠標檢測的代碼跑一跑試試。
右邊顯示臨時顯示字符用于測試連通性,多次測試沒有問題。
最后加上連線,并清除被點擊的兩個格子,就完成了連連看的核心邏輯:
文明看帖,點贊+關注+收藏一波走起~
代碼獲取方式
由于平臺不能放文件小編將源碼放在C語言/C++學習交流群:836880131!群里還整理了一些個人覺得比較好的學習書籍、視頻資料共享在群文件里面,有需要的可以自行添加!