经过四次的修改和优化,终于将推箱子这个游戏完整的写出来了,今天就像大家分享一下这个游戏的编写。
这个游戏界面的编写总的来说不困难,主要是推动箱子的算法。
(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 }
头文件
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 }; 24 25 int PushBox::move(int map[N][M], char ch) 26 { 27 28 static int step = 0; 29 int x1, x2, y1, y2; 30 switch (ch) 31 { 32 case 's': 33 case 'S': x1 = 1; x2 = 2; y1 = 0; y2 = 0; 34 if (push(map, x1, x2, y1, y2)) step++; return step; 35 36 case 'w': 37 case 'W': x1 = -1; x2 = -2; y1 = 0; y2 = 0; 38 if (push(map,x1,x2,y1,y2)) step++; return step; 39 40 case 'A': 41 case 'a': x1 = 0; x2 = 0; y1 = -1; y2 = -2; 42 if (push(map,x1,x2,y1,y2)) step++; return step; 43 case 'D': 44 case 'd': x1 = 0; x2 = 0; y1 = 1; y2 = 2; 45 if (push(map,x1,x2,y1,y2)) step++; return step; 46 } 47 } 48 49 void PushBox::Drop(int map[N][M]) 50 { 51 int i, j; 52 for (i = 0; i < N; i++) 53 { 54 for (j = 0; j < M; j++) 55 switch (map[i][j]) 56 { 57 case 0: Color(7); std::cout << " "; break; 58 case 1: Color(4); std::cout << "■"; break; 59 case 2: Color(10); std::cout << "△"; break; 60 case 3: Color(5); std::cout << "□"; break; 61 case 4: Color(1); std::cout << "☆"; break; 62 case 5: Color(7); std::cout << "◆"; break; 63 case 6: Color(10); std::cout << "△"; break; 64 65 } 66 std::cout << "\n"; 67 } 68 } 69 70 int PushBox::juide(int map[N][M]) 71 { 72 int i, j; 73 for (i = 0; i < N; i++) 74 { 75 for (j = 0; j < M; j++) 76 { 77 if (map[i][j] == 6)return 0; 78 if (map[i][j] == 4)return 0; 79 } 80 81 if (i == N - 1 && j == M - 1)return 1; 82 } 83 } 84 85 int PushBox::push(int map[N][M],int x1,int x2,int y1,int y2) 86 { 87 int i, j; 88 Postion(map, &i, &j); 89 /*******************人在空格处*/ 90 if (map[i][j] == 2) 91 { 92 //人前是箱子,箱子在空格处 93 if (map[i + x1][j + y1] == 3) 94 { //箱子前面为空格S 95 if (map[i + x2][j + y2] == 0) 96 { 97 map[i][j] = 0; 98 map[i + x1][j + y1] = 2; 99 map[i + x2][j + y2] = 3; 100 return 1; 101 } 102 //箱子前面为位置 103 if (map[i + x2][j + y2] == 4) 104 { 105 map[i][j] = 0; 106 map[i + x1][j + y1] = 2; 107 map[i + x2][j + y2] = 5; 108 return 1; 109 } 110 } 111 //人前为箱子,箱子在位置上 112 if (map[i + x1][j + y1] == 5) 113 { 114 //箱子前面为空 115 if (map[i + x2][j + y2] == 0) 116 { 117 map[i + x2][j + y2] = 3; 118 map[i + x1][j + y1] = 6; 119 map[i][j] = 0; 120 return 1; 121 122 } 123 //箱子前面为位置 124 if (map[i + x2][j + y2] == 4) 125 { 126 map[i][j] = 0; 127 map[i + x1][j + y1] = 6; 128 map[i + x2][j + y2] = 5; 129 return 1; 130 } 131 132 } 133 /*--------------------*/ 134 //人前为空格 135 if (map[i + x1][j + y1] == 0) 136 { 137 map[i + x1][j + y1] = 2; 138 map[i][j] = 0; 139 return 1; 140 } 141 //人前为位置 142 if (map[i + x1][j + y1] == 4) 143 { 144 map[i + x1][j + y1] = 6; 145 map[i][j] = 0; 146 return 1; 147 } 148 return 0; 149 } 150 /*******************人在位置上*/ 151 if (map[i][j] == 6) 152 { 153 //位置前面是箱子,箱子在空格 154 if (map[i + x1][j + y1] == 3) 155 { 156 //箱子前面为空格 157 if (map[i + x2][j + y2] == 0) 158 { 159 map[i][j] = 4; 160 map[i + x1][j + y1] = 2; 161 map[i + x2][j + y2] = 3; 162 return 1; 163 } 164 //箱子前面为位置 165 if (map[i + x2][j + y2] == 4) 166 { 167 map[i][j] = 4; 168 map[i + x1][j + y1] = 2; 169 map[i + x2][j + y2] = 5; 170 return 1; 171 } 172 } 173 //位置前面是箱子,箱子在位置 174 if (map[i + x1][j + y1] == 5) 175 { 176 //箱子前面是空格 177 if (map[i + x2][j + y2] == 0) 178 { 179 map[i][j] = 4; 180 map[i + x1][j + y1] = 6; 181 map[i + x2][j + y2] = 3; 182 return 1; 183 } 184 //箱子前面是位置 185 if (map[i + x2][j + y2] == 4) 186 { 187 map[i][j] = 4; 188 map[i + x1][j + y1] = 6; 189 map[i + x2][j + y2] = 5; 190 return 1; 191 } 192 } 193 194 /*-----------------*/ 195 //人前为位置 196 if (map[i + x1][j + y1] == 4) 197 { 198 map[i + x1][j + y1] = 6; 199 map[i][j] = 4; 200 return 1; 201 } 202 //人前为空格 203 if (map[i + x1][j + y1] == 0) 204 { 205 map[i + x1][j + y1] = 2; 206 map[i][j] = 4; 207 return 1; 208 } 209 return 0; 210 }return 0; 211 } 212 213 void PushBox::Postion(int map[N][M], int *cl, int *cow) 214 { 215 int i, j; 216 for (i = 0; i < N; i++) 217 { 218 for (j = 0; j < M; j++) 219 { 220 if (map[i][j] == 2 || map[i][j] == 6)goto ML; 221 } 222 }ML: 223 *cl = i; 224 *cow = j; 225 ; 226 } 227 228 void PushBox::Color(int m) 229 { 230 HANDLE consolehwnd;//创建句柄,详细句柄知识,请百度一下或查MSDN 231 consolehwnd = GetStdHandle(STD_OUTPUT_HANDLE);//实例化句柄 232 SetConsoleTextAttribute(consolehwnd, m); 233 }
两个地图张
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 4 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 1 1 1 3 1 1 1 1 0 0 0 0 0 0 1 4 0 0 3 2 3 4 1 0 0 0 0 0 0 1 1 1 1 1 3 1 1 1 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 4 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 1 2 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 3 3 1 0 1 1 1 0 0 0 0 0 0 1 0 3 0 1 0 1 4 1 0 0 0 0 0 0 1 1 1 0 1 1 1 4 1 0 0 0 0 0 0 0 1 1 0 0 0 0 4 1 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
文件放置如图: