经过四次的修改和优化,终于将推箱子这个游戏完整的写出来了,今天就像大家分享一下这个游戏的编写。
这个游戏界面的编写总的来说不困难,主要是推动箱子的算法。
(1)利用数组和windows api 即可写出界面
1 #define N 15 2 #define M 15 3 int map[N][M] = { 4 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 5 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 6 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 7 { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 },//0->空白 8 { 0, 0, 0, 0, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0 },//1->墙 9 { 0, 0, 0, 0, 1, 0, 3, 0, 0, 1, 0, 0, 0, 0, 0 },//2->人 10 { 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0 },//3->箱子 11 { 0, 0, 0, 1, 4, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0 },//4->位置 12 { 0, 0, 0, 1, 4, 3, 0, 0, 1, 0, 1, 0, 0, 0, 0 }, 13 { 0, 0, 0, 1, 4, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0 }, 14 { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, 15 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 16 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 17 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 18 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 19 20 void PushBox::Color(int m)//封装到PushBox类里 21 { 22 HANDLE consolehwnd;//创建句柄,详细句柄知识,请百度一下或查MSDN 23 consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE);//实例化句柄 24 SetConsoleTextAttribute(consolehwnd, m); 25 } 26 27 28 29 void PushBox::Drop(int map[N][M]) 30 { 31 int i, j; 32 for (i = 0; i < N; i++) 33 { 34 for (j = 0; j < M; j++) 35 switch (map[i][j]) 36 { 37 case 0: Color(7); std::cout << " "; break; 38 case 1: Color(4); std::cout << "■"; break; 39 case 2: Color(10); std::cout << "△"; break; 40 case 3: Color(5); std::cout << "□"; break; 41 case 4: Color(1); std::cout << "☆"; break; 42 case 5: Color(7); std::cout << "◆"; break;//箱子到达目标位置 43 case 6: Color(10); std::cout << "△"; break;//表示人与位置重叠 44 45 } 46 std::cout << "\n"; 47 } 48 }
(2)推箱子算法:本人比较笨,没有找到捷径,所以就穷举了推箱子步骤,分析如下:
以人为中心,出现两种可能:①人在空位 ②人在目标位置上
①有六种可能:(注:x1,y1, x2, y2为坐标的偏移量,i ,为人所在的坐标 )
②人在目标位置上 同样也有六种可能:
用if语句进行对这12中可能进行判断,除了处理这几种能够移动的外,其他没有可能移动,分析清楚,则很容写出移动算法:
1 int PushBox::push(int map[N][M],int x1,int x2,int y1,int y2) 2 { 3 int i, j; 4 Postion(map, &i, &j); 5 /*******************人在空格处*/ 6 if (map[i][j] == 2) 7 { 8 //人前是箱子,箱子在空格处 9 if (map[i + x1][j + y1] == 3) 10 { //箱子前面为空格S 11 if (map[i + x2][j + y2] == 0) 12 { 13 map[i][j] = 0; 14 map[i + x1][j + y1] = 2; 15 map[i + x2][j + y2] = 3; 16 return 1; 17 } 18 //箱子前面为位置 19 if (map[i + x2][j + y2] == 4) 20 { 21 map[i][j] = 0; 22 map[i + x1][j + y1] = 2; 23 map[i + x2][j + y2] = 5; 24 return 1; 25 } 26 } 27 //人前为箱子,箱子在位置上 28 if (map[i + x1][j + y1] == 5) 29 { 30 //箱子前面为空 31 if (map[i + x2][j + y2] == 0) 32 { 33 map[i + x2][j + y2] = 3; 34 map[i + x1][j + y1] = 6; 35 map[i][j] = 0; 36 return 1; 37 38 } 39 //箱子前面为位置 40 if (map[i + x2][j + y2] == 4) 41 { 42 map[i][j] = 0; 43 map[i + x1][j + y1] = 6; 44 map[i + x2][j + y2] = 5; 45 return 1; 46 } 47 48 } 49 /*--------------------*/ 50 //人前为空格 51 if (map[i + x1][j + y1] == 0) 52 { 53 map[i + x1][j + y1] = 2; 54 map[i][j] = 0; 55 return 1; 56 } 57 //人前为位置 58 if (map[i + x1][j + y1] == 4) 59 { 60 map[i + x1][j + y1] = 6; 61 map[i][j] = 0; 62 return 1; 63 } 64 return 0; 65 } 66 /*******************人在位置上*/ 67 if (map[i][j] == 6) 68 { 69 //位置前面是箱子,箱子在空格 70 if (map[i + x1][j + y1] == 3) 71 { 72 //箱子前面为空格 73 if (map[i + x2][j + y2] == 0) 74 { 75 map[i][j] = 4; 76 map[i + x1][j + y1] = 2; 77 map[i + x2][j + y2] = 3; 78 return 1; 79 } 80 //箱子前面为位置 81 if (map[i + x2][j + y2] == 4) 82 { 83 map[i][j] = 4; 84 map[i + x1][j + y1] = 2; 85 map[i + x2][j + y2] = 5; 86 return 1; 87 } 88 } 89 //位置前面是箱子,箱子在位置 90 if (map[i + x1][j + y1] == 5) 91 { 92 //箱子前面是空格 93 if (map[i + x2][j + y2] == 0) 94 { 95 map[i][j] = 4; 96 map[i + x1][j + y1] = 6; 97 map[i + x2][j + y2] = 3; 98 return 1; 99 } 100 //箱子前面是位置 101 if (map[i + x2][j + y2] == 4) 102 { 103 map[i][j] = 4; 104 map[i + x1][j + y1] = 6; 105 map[i + x2][j + y2] = 5; 106 return 1; 107 } 108 } 109 110 /*-----------------*/ 111 //人前为位置 112 if (map[i + x1][j + y1] == 4) 113 { 114 map[i + x1][j + y1] = 6; 115 map[i][j] = 4; 116 return 1; 117 } 118 //人前为空格 119 if (map[i + x1][j + y1] == 0) 120 { 121 map[i + x1][j + y1] = 2; 122 map[i][j] = 4; 123 return 1; 124 } 125 return 0; 126 }return 0; 127 }
这里写返回1值既可以减少系统的判断,还可以判断是否执行了移动操作,方便统计移动的步数
(3)编写获取人的位置函数、判断是否获胜
获取人的位置,只需要判断得到地图中6或者2其中一个坐标,由于需要横坐标和纵坐标,所以利用指针得到位置
void PushBox::Postion(int map[N][M], int *cl, int *cow) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { if (map[i][j] == 2 || map[i][j] == 6)goto ML; } }ML: *cl = i; *cow = j; }
判断是否获胜:即地图中没有目标位置,就获胜,若胜利返回1值,否则返回0;
int PushBox::juide(int map[N][M]) { int i, j; for (i = 0; i < N; i++) { for (j = 0; j < M; j++) { if (map[i][j] == 6)return 0; if (map[i][j] == 4)return 0; } if (i == N - 1 && j == M - 1)return 1; } }
(4)编写移动方向算法,并统计执行步数
int PushBox::move(int map[N][M], char ch) { static int step = 0; int x1, x2, y1, y2; switch (ch) { case 's': case 'S': x1 = 1; x2 = 2; y1 = 0; y2 = 0; if (push(map, x1, x2, y1, y2)) step++; return step; case 'w': case 'W': x1 = -1; x2 = -2; y1 = 0; y2 = 0; if (push(map,x1,x2,y1,y2)) step++; return step; case 'A': case 'a': x1 = 0; x2 = 0; y1 = -1; y2 = -2; if (push(map,x1,x2,y1,y2)) step++; return step; case 'D': case 'd': x1 = 0; x2 = 0; y1 = 1; y2 = 2; if (push(map,x1,x2,y1,y2)) step++; return step; } }
(5)Push类的封装,将以上的几个方法封装到类里,建立头文件
1 #include <iostream> 2 using namespace std; 3 #include <windows.h> 4 #include <string.h> 5 #include <conio.h> 6 #include <fstream> 7 #pragma warning(disable:4996) 8 #define N 15 9 #define M 15 10 11 //建立一个推箱子相关操作的类 12 /*--------------------------PushBox类编写--------------------------------------*/ 13 /****************************************************************************/ 14 class PushBox{ 15 public: 16 int move(int map[N][M], char ch);//移动箱子 17 void Drop(int map[N][M]);//箱子界面编写 18 int juide(int map[N][M]);//判断是否全部移入位置,成功返回1,失败返回0 19 private: 20 int push(int map[N][M],int x1,int x2,int y1,int y2); 21 void Color(int m); 22 void Postion(int map[N][M], int *i, int *j); 23 };
(6)主函数的编写:这里我将地图放入外部txt文件中,方便以后添加地图
#include <iostream> using namespace std; #include <windows.h> #include <string.h> #include <conio.h> #include "Push.h" #pragma warning(disable:4996) #define N 15 #define M 15 int read_map(int *p); void change_map(int *p, char *temp); //主函数 int main() { int map[N][M] = { 0 }; PushBox box; int *p = &map[0][0]; int select = read_map(p); int step = 0; while (1) { cout << "你选择的关卡是:" << select << endl; cout << "你走了:" << step << "步"; box.Drop(map); cout << "W-----向上 S------向下" << endl; cout << "A-----向左 S------向右" << endl; char ch; ch = _getch(); step = box.move(map, ch); system("cls"); if (box.juide(map))break; } std::cout << "你赢了!"; std::cout << "共走:" << step << "步"; getchar(); getchar(); } /*选择关卡*/ int read_map(int *p) { int ch; cout << "请输入关卡:"; cin >> ch; char temp[15]; switch (ch) { case 1:strcpy(temp, "map/map_1.txt"); change_map(p, temp); system("cls"); return 1; case 2:strcpy(temp, "map/map_2.txt"); change_map(p, temp); system("cls"); return 1; } } /*打开关卡*/ void change_map(int *p, char *temp) { ifstream infile; infile.open(temp); while (!infile.eof()) { infile >> *p; p++; } infile.close(); }
程序分析图:
经过调试运行,暂时还没有发现BUG,一下是源代码,希望大家发现了以后给我留言,写得不好的地方希望大家能够指出
源文件
1 /************************************************** 2 * Name : 推箱子 3 * FileName : PushBox.cpp 4 * Author : 和导 5 * Version : V4.0 6 * Date : 7 *Description : 制作一个简单的推箱子 8 9 *Function List : (1)void read_map(int *p); 10 (2)void change_map(int *p, char *temp); 11 -------------- 12 History: 13 <author> <time> <reviseInf> 14 和导 2016/4/1 把类封装到头文件中,重写推函数,添加地图 15 ****************************************************/ 16 17 18 #include <iostream> 19 using namespace std; 20 #include <windows.h> 21 #include <string.h> 22 #include <conio.h> 23 #include "Push.h" 24 #pragma warning(disable:4996) 25 #define N 15 26 #define M 15 27 28 int read_map(int *p); 29 void change_map(int *p, char *temp); 30 //主函数 31 32 int main() 33 { 34 int map[N][M] = { 0 }; 35 PushBox box; 36 int *p = &map[0][0]; 37 int select = read_map(p); 38 int step = 0; 39 while (1) 40 { 41 cout << "你选择的关卡是:" << select << endl; 42 cout << "你走了:" << step << "步"; 43 box.Drop(map); 44 cout << "W-----向上 S------向下" << endl; 45 cout << "A-----向左 S------向右" << endl; 46 char ch; 47 ch = _getch(); 48 step = box.move(map, ch); 49 system("cls"); 50 if (box.juide(map))break; 51 } 52 std::cout << "你赢了!"; 53 std::cout << "共走:" << step << "步"; 54 getchar(); 55 getchar(); 56 } 57 58 59 60 /*选择关卡*/ 61 int read_map(int *p) 62 { 63 int ch; 64 cout << "请输入关卡:"; 65 cin >> ch; 66 char temp[15]; 67 switch (ch) 68 { 69 case 1:strcpy(temp, "map/map_1.txt"); change_map(p, temp); system("cls"); return 1; 70 case 2:strcpy(temp, "map/map_2.txt"); change_map(p, temp); system("cls"); return 1; 71 } 72 73 } 74 /*打开关卡*/ 75 void change_map(int *p, char *temp) 76 { 77 ifstream infile; 78 infile.open(temp); 79 while (!infile.eof()) 80 { 81 infile >> *p; 82 p++; 83 } 84 infile.close(); 85 }