寫在前面
在知乎上偶爾看到有人利用寫這種小程序練手,正好最近剛考完期末考試,所以就花了一個晚上寫了一下,也簡單的寫了一個2048.
以下是效果圖
之前沒有用c++寫過比較大型的內容,對c++的理解也不是很深。所以經過這一次編寫,對游戲算法的理解以及c++多文件之間的調用有了更深刻的理解。
在寫之前,我先簡單的構思了以下整個游戲會分成哪幾個部分,私以為可以簡單的分為六個部分:
- 初始化游戲地圖
- 在游戲地圖內格子隨機生成一個數字
- 在屏幕上顯示出地圖
- 玩家輸入操控指令
- 程序對玩家的指令進行相應移動與合并
- 判斷游戲是否結束,若沒有結束就跳到2,否則跳出
我發現這六點當中,只有第5點最有難度,也就是如何去移動整個表盤中的元素,如何判別是否可以合并,四個方向上的移動合并有什么共同點和差別,如何合并等內容。其他5點就很簡單了,基本上沒有這么復雜的邏輯。
下面我就以這6點分別進行講解。
主程序
將主程序放在單獨的一個文件內
//source.cpp
#include <iostream>
#include <Windows.h>
#include "OperateMap.h"
#include "Parameter.h"
using namespace std;
int main() {
//游戲地圖
int MAP[MAP_SIZE][MAP_SIZE];
//初始化地圖
Initlize(MAP);
bool isFull = false;
int score = 0;
while (!isFull) {
//刷新窗口
system("cls");
//生成數字
Generate(MAP);
//顯示地圖
ShowMap(MAP, score);
//輸入指令
char command;
cin >> command;
//移動地圖
MoveMap(MAP, command, score);
//是否結束?
isFull = IsOver(MAP);
}
system("pause");
return 0;
}
可以看出我引用了兩個自定義的文件,即OperateMap.h和Parameter.h。
OperateMap.h定義了主函數中所用到的Initlize(), Generate(), ShowMap(), MoveMap(), IsOver()等函數。
Parameter.h則定義了一些重要的參數,諸如地圖大小MAP_SIZE。
程序的邏輯比較容易看懂,就是很簡單的判斷isFull是否為ture,也就是地圖滿了沒,如果滿了,那就是游戲結束。
初始化地圖
初始化地圖所用到的函數為Initlize(),具體實現過程如下
void Initlize(int(&MAP)[MAP_SIZE][MAP_SIZE]) {
/*初始化地圖MAP*/
cerr << "-----Initlize Finish!" << endl;
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
MAP[i][j] = 0;
}
}
}
也就是通過引用傳遞MAP將其內所有元素設置為0.
隨機生成數字
在上面已經將地圖初始化了,但是全部格點都是0,在呈現給玩家看之前就需要先隨機生成一個點,這一步就是解決這一個問題的。
在剛開始的時候,我是從整個地圖中隨機生成一個坐標,然后賦值2或者4。但是這樣子會讓程序效率十分低下,因為在后期格子只有少數幾個為0的情況下,隨機很難直接隨機到那幾個點,所以會導致不斷的生成坐標點,效率極其低下。
為此做的對應的修改就是,首先將地圖遍歷一遍,記錄當前為0的格點,然后從這些格點當中抽出一個賦值為2或4即可。
對應的代碼如下
void Generate(int(&MAP)[MAP_SIZE][MAP_SIZE]) {
/*在地圖中生成隨機數*/
//判斷生成2還是4
int randNum[2] = { 2, 4 };
int chose24;
if (Rand021() <= 0.5) chose24 = 2;
else chose24 = 4;
int noZeroMAP[MAP_SIZE*MAP_SIZE][2], noZeroNum = 0;
//將不是0的格子保存下來, 從中選出一個生成
for (int i = 0; i < MAP_SIZE; i++) {
for(int j = 0; j < MAP_SIZE; j++) {
if (MAP[i][j] != 0) {
noZeroMAP[noZeroNum][0] = i;
noZeroMAP[noZeroNum][1] = j;
noZeroNum++;
}
}
}
int generatePos = RandA2B(0, noZeroNum-1);
MAP[noZeroMAP[noZeroNum][0]][noZeroMAP[noZeroNum][1]] = chose24;
}
這里用到的Rand021()是隨機生成0到1之間的隨機浮點數,和RandA2B()是隨機生成A到B之間的隨機整數,具體定義如下
//Rand.cpp
#include <cstdlib>
#include <ctime>
double Rand021() {
srand((int)time(0));
return rand() / double(RAND_MAX);
}
int RandA2B(int A, int B) {
srand((int)time(0));
return rand() % (B - A + 1) + A;
}
顯示地圖
顯示地圖相當于沒什么技術含量了,就是簡單粗暴的直接輸出就好。不過為了地圖更好看,將0替換成-進行輸出。
void ShowMap(int(&MAP)[MAP_SIZE][MAP_SIZE], int score) {
/*輸出地圖*/
cout << "Now Your Game Map is: " << endl;
cout << "---------------------------------" << endl;
for (int i = 0; i < MAP_SIZE; i++) {
for (int j = 0; j < MAP_SIZE; j++) {
if (MAP[i][j] == 0) cout << " " << "-";
else cout << " " << MAP[i][j];
}
cout << endl;
}
cout << "---------------------------------" << endl;
cout << "Now Your Score is: " << score << endl;
cout << "Plase Move Map(up:w down:s left:a right:d): ";
}
告一段落
下一部分就是移動地圖的內容了,內容比較多,所以我放在下一篇文章中進行講解。
如果有幫助的話還麻煩點個關注點個贊噢~
全部代碼放在我的GitHub中。