震惊——全网注释最详细的推箱子源代码竟是一名大一学生所做 ~~(来自UC震惊部)
步入正题:主要为大家介绍了用C语言实现简单的推箱子小游戏,有兴趣的小伙伴可以参考一下。下面分块给出源代码,并附有详细注释。
游戏流程(在主函数中实现)
1.打印菜单界面
2.初始化地图
3.玩家进行操作
4.判断游戏是否结束(若未结束,则循环2、3步骤)
5.结束后询问玩家是否继续
6.若玩家选择继续游戏,则循环2、3、4步骤,否则退出程序。
程序中用到的头文件及自定义函数,功能已写出
#include<stdio.h>
#include
#define LEVEL 3 //地图数量(关卡数量)
#define WIDTH 9 //定义地图宽度
#define HEIGHT 9 //定义地图高度
void moveUp(); //向上移动
void moveDown(); //向下移动
void moveLeft(); //向左移动
void moveRight(); //向右移动
void initialMap(); //初始化地图
void initialData(); //初始化数据
int boxs = 0; //全局变量:箱子个数
int choice; //全局变量:选择地图
int x, y; //全局变量:表示人的坐标
用二维数组存储地图,根据数组中不同数字打印地图中不同元素,目前仅有三个地图,有兴趣的同学可自行设计地图,体验更多关卡的乐趣~
int map[LEVEL][WIDTH][HEIGHT] = {
{
{
0, 0, 0, 0, 0, 0, 0, 0},
{
0, 1, 1, 1, 1, 1, 1, 0},
{
0, 1, 4, 0, 0, 0, 1, 0},
{
0, 1, 0, 2, 0, 0, 1, 0},
{
0, 1, 0, 0, 3, 0, 1, 0},
{
0, 1, 0, 0, 0, 0, 1, 0},
{
0, 1, 1, 1, 1, 1, 1, 0},
{
0, 0, 0, 0, 0, 0, 0, 0},
},
{
{
0, 0, 1, 1, 1, 0, 0, 0, 0},
{
0, 0, 1, 4, 1, 0, 0, 0, 0},
{
0, 0, 1, 0, 1, 1, 1, 1, 0},
{
1, 1, 1, 3, 0, 3, 4, 1, 0},
{
1, 4, 0, 3, 2, 1, 1, 1, 0},
{
1, 1, 1, 1, 3, 1, 0, 0, 0},
{
0, 0, 0, 1, 4, 1, 0, 0, 0},
{
0, 0, 0, 1, 1, 1, 0, 0, 0},
},
{
{
1, 1, 1, 1, 1, 0, 0, 0, 0},
{
1, 0, 0, 0, 1, 0, 0, 0, 0},
{
1, 0, 3, 3, 1, 0, 1, 1, 1},
{
1, 2, 3, 0, 1, 0, 1, 4, 1},
{
1, 1, 1, 0, 1, 1, 1, 4, 1},
{
0, 1, 1, 0, 0, 0, 0, 4, 1},
{
0, 1, 0, 0, 0, 1, 0, 0, 1},
{
0, 1, 0, 0, 0, 1, 1, 1, 1},
{
0, 1, 1, 1, 1, 1, 0, 0, 0},
}
};
初始化地图函数
void initialMap() //初始化地图
{
int i, j;
for(i=0;i<WIDTH;i++)
{
for(j=0;j<HEIGHT;j++)
{
switch(map[choice][i][j])
{
case 0:
printf(" "); //0代表空地
break;
case 1:
printf("■"); //1代表墙体
break;
case 2:
printf("♀"); //2代表玩家(人)
break;
case 3:
printf("◆"); //3代表箱子
break;
case 4:
printf("●"); //4代表目的地
break;
case 5:
printf("★"); //5代表已到达目的地的箱子
break;
case 6:
printf("♀"); //6代表站在目的地上的人
break;
}
}
printf("\n");
}
}
初始化数据(箱子数量,人的坐标)
void initialData()
{
int i, j;
printf("游戏加载中,请稍后.........");
//遍历地图中的数据
for(i = 0; i < HEIGHT; i++)
{
for(j = 0; j < WIDTH; j++)
{
//遍历到2(人)时,记录人的坐标。x, y是前面定义的全局变量
if(map[choice][i][j] == 2)
{
x = j;
y = i;
}
//遍历到3时,箱子的数目增加。boxs是前面定义的全局变量
if(map[choice][i][j] == 3)
{
boxs++;
}
}
}
}
向上移动函数
void moveUp()
{
int ux, uy; //定义变量存放人物上方的坐标
if(y == 0) //当上方没有元素时,直接return (其实人不可能在边缘)
{
return ;
}
ux = x; //记录上方坐标,x为横,y为纵,所以ux = x, uy = y - 1;
uy = y - 1;
if(map[choice][uy][ux] == 0) //如果人的前面是空地
{
map[choice][uy][ux] = 2; //人前方变为人
if(map[choice][uy+1][ux] == 6) //判断初始人的位置
{
map[choice][uy+1][ux] = 4;
}else
{
map[choice][uy+1][ux] = 0;
}
}
if(map[choice][uy][ux] == 1)//假设上方为墙,直接return,这个和上面的判断可以合在一起,这里为了看清楚分开写
{
return;
}
if(map[choice][uy][ux] == 3) //假设上方为箱子
{
if(map[choice][uy - 1][ux] == 1) //判断箱子上方是否为墙
{
return;
}
if(map[choice][uy - 1][ux] == 3) //判断箱子上边是否为箱子
{
return;
}
if(map[choice][uy - 1][ux] == 4) //判断箱子上方是否为终点
{
map[choice][uy - 1][ux] = 5; //将箱子上面内容赋值为5★
map[choice][uy][ux] = 2;
if(map[choice][uy+1][ux] == 6) //判断初始人的位置
{
map[choice][uy+1][ux] = 4;
}else
{
map[choice][uy+1][ux] = 0;
}
boxs--; //箱子的数目减1
}
else
{
map[choice][uy - 1][ux] = 3; //移动箱子
map[choice][uy][ux] = 2;
if(map[choice][uy+1][ux] == 6) //判断初始人的位置
{
map[choice][uy+1][ux] = 4;
}else
{
map[choice][uy+1][ux] = 0;
}
}
}
if(map[choice][uy][ux] == 4)
{
map[choice][uy][ux] = 6;
if(map[choice][uy+1][ux] == 6) //判断初始人的位置
{
map[choice][uy+1][ux] = 4;
}else
{
map[choice][uy+1][ux] = 0;
}
}
if(map[choice][uy][ux] == 5) //上方为已完成的箱子
{
if(map[choice][uy-1][ux] == 4) //如果上方为目标
{
map[choice][uy-1][ux] = 5; //将上方赋值为已完成的箱子
map[choice][uy][ux] = 6; //变为被人遮盖的目标
if(map[choice][uy+1][ux] == 6) //将原位置变空
{
map[choice][uy+1][ux] = 4;
}else
{
map[choice][uy+1][ux] = 0;
}
}
}
y = uy; //更新人的坐标
}
向下移动函数(由于四个方向移动函数结构类似,注释类比向上移动函数)
void moveDown()
{
int dx, dy; //定义变量存放人物下方的坐标
dx = x; //记录下边坐标,x为横,y为纵,所以dx = x, dy = y + 1;
dy = y + 1;
if(map[choice][dy][dx] == 0)//如果人的前面是空地
{
map[choice][dy][dx] = 2; //人前方变为人
if(map[choice][dy-1][dx] == 6)
{
map[choice][dy-1][dx] = 4;
}else
{
map[choice][dy-1][dx] = 0;
}
}
if(map[choice][dy][dx] == 1)//假设下方为墙,直接return,这个和上面的判断可以合在一起,这里为了看清楚分开写
{
return;
}
if(map[choice][dy][dx] == 3) //假设下方为箱子
{
if(map[choice][dy + 1][dx] == 1) //判断箱子下方是否为墙
{
return;
}
if(map[choice][dy + 1][dx] == 3) //判断箱子下边是否为箱子
{
return;
}
if(map[choice][dy + 1][dx] == 4) //判断箱子下方是否为目标
{
map[choice][dy + 1][dx] = 5; //将箱子上面内容赋值为5★
map[choice][dy][dx] = 2;
if(map[choice][dy-1][dx] == 6)
{
map[choice][dy-1][dx] = 4;
}else
{
map[choice][dy-1][dx] = 0;
}
boxs--; //箱子的数目减1
}
else
{
map[choice][dy + 1][dx] = 3; //移动箱子
map[choice][dy][dx] = 2;
if(map[choice][dy-1][dx] == 6)
{
map[choice][dy-1][dx] = 4;
}else
{
map[choice][dy-1][dx] = 0;
}
}
}
if(map[choice][dy][dx] == 4)
{
map[choice][dy][dx] = 6;
if(map[choice][dy-1][dx] == 6)
{
map[choice][dy-1][dx] = 4;
}else
{
map[choice][dy-1][dx] = 0;
}
}
if(map[choice][dy][dx] == 5) //上方为已完成的箱子
{
if(map[choice][dy+1][dx] == 4) //如果上方为目标
{
map[choice][dy+1][dx] = 5; //将上方赋值为已完成的箱子
map[choice][dy][dx] = 6; //变为被人遮盖的目标
if(map[choice][dy-1][dx] == 6) //将原位置变空
{
map[choice][dy-1][dx] = 4;
}else
{
map[choice][dy-1][dx] = 0;
}
}
}
y = dy; //更新人的坐标
}
向左移动函数(由于四个方向移动函数结构类似,注释类比向上移动函数)
void moveLeft()
{
int lx, ly; //定义变量存放人物上方的坐标
lx = x-1; //记录上方坐标,x为横,y为纵,所以ux = x, uy = y - 1;
ly = y;
if(map[choice][ly][lx] == 0)//如果人的前面是空地
{
map[choice][ly][lx] = 2; //人前方变为人
if(map[choice][ly][lx+1] == 6)
{
map[choice][ly][lx+1] = 4;
}else
{
map[choice][ly][lx+1] = 0;
}
}
if(map[choice][ly][lx] == 1)//假设上方为墙,直接return,这个和上面的判断可以合在一起,这里为了看清楚分开写
{
return;
}
if(map[choice][ly][lx] == 3) //假设上方为箱子
{
if(map[choice][ly][lx-1] == 1) //判断箱子左边是否为墙
{
return;
}
if(map[choice][ly][lx-1] == 3) //判断箱子左边是否为箱子
{
return;
}
if(map[choice][ly][lx-1] == 4) //判断箱子左边是否为终点
{
map[choice][ly][lx-1] = 5; //将箱子左边赋值为5★
map[choice][ly][lx] = 2;
if(map[choice][ly][lx+1] == 6)
{
map[choice][ly][lx+1] = 4;
}else
{
map[choice][ly][lx+1] = 0;
}
boxs--; //箱子的数目减1
}
else
{
map[choice][ly][lx-1] = 3; //移动箱子
map[choice][ly][lx] = 2;
if(map[choice][ly][lx+1] == 6)
{
map[choice][ly][lx+1] = 4;
}else
{
map[choice][ly][lx+1] = 0;
}
}
}
if(map[choice][ly][lx] == 4)
{
map[choice][ly][lx] = 6;
if(map[choice][ly][lx+1] == 6)
{
map[choice][ly][lx+1] = 4;
}else
{
map[choice][ly][lx+1] = 0;
}
}
if(map[choice][ly][lx] == 5) //上方为已完成的箱子
{
if(map[choice][ly][lx-1] == 4) //如果上方为目标
{
map[choice][ly][lx-1] = 5; //将上方赋值为已完成的箱子
map[choice][ly][lx] = 6; //变为被人遮盖的目标
if(map[choice][ly][lx+1] == 6) //将原位置变空
{
map[choice][ly][lx+1] = 4;
}else
{
map[choice][ly][lx+1] = 0;
}
}
}
x = lx; //更新人的坐标
}
向右移动函数(由于四个方向移动函数结构类似,注释类比向上移动函数)
void moveRight()
{
int rx, ry; //定义变量存放人物右边的坐标
rx = x+1; //记录上方坐标,x为横,y为纵,所以rx = x+1, ry = y;
ry = y;
if(map[choice][ry][rx] == 0) //如果人的前面是空地
{
map[choice][ry][rx] = 2; //人前方变为人
if(map[choice][ry][rx-1] == 6)
{
map[choice][ry][rx-1] = 4;
}else
{
map[choice][ry][rx-1] = 0;
}
}
if(map[choice][ry][rx] == 1) //假设右边为墙,直接return,这个和上面的判断可以合在一起,这里为了看清楚分开写
{
return;
}
if(map[choice][ry][rx] == 3) //假设右边为箱子
{
if(map[choice][ry][rx+1] == 1) //判断箱子右边是否为墙
{
return;
}
if(map[choice][ry][rx+1] == 3) //判断箱子右边是否为箱子
{
return;
}
if(map[choice][ry][rx+1] == 4) //判断箱子上方是否为终点
{
map[choice][ry][rx+1] = 5; //将箱子上面内容赋值为5★
map[choice][ry][rx] = 2;
if(map[choice][ry][rx-1] == 6)
{
map[choice][ry][rx-1] = 4;
}else
{
map[choice][ry][rx-1] = 0;
}
boxs--; //箱子的数目减1
}
else
{
map[choice][ry][rx+1] = 3; //移动箱子
map[choice][ry][rx] = 2;
if(map[choice][ry][rx-1] == 6)
{
map[choice][ry][rx-1] = 4;
}else
{
map[choice][ry][rx-1] = 0;
}
}
}
if(map[choice][ry][rx] == 4)
{
map[choice][ry][rx] = 6;
if(map[choice][ry][rx-1] == 6)
{
map[choice][ry][rx-1] = 4;
}else
{
map[choice][ry][rx-1] = 0;
}
}
if(map[choice][ry][rx] == 5) //上方为已完成的箱子
{
if(map[choice][ry][rx+1] == 4) //如果上方为目标
{
map[choice][ry][rx+1] = 5; //将上方赋值为已完成的箱子
map[choice][ry][rx] = 6; //变为被人遮盖的目标
if(map[choice][ry][rx-1] == 6) //将原位置变空
{
map[choice][ry][rx-1] = 4;
}else
{
map[choice][ry][rx-1] = 0;
}
}
}
x = rx; //更新人的坐标
}
在主函数中实现推箱子功能
int main(void)
{
char direction, q;
printf("******************************************************\n");
printf("***** 欢迎来到推箱子大赛 *****\n");
printf("***** 本游戏由Mr.Sang制作 *****\n");
printf("******************************************************\n");
printf("***************************\n");
printf(" 是否要开始游戏?(y/n)\n");
printf("***************************\n");
while(scanf(" %c",&q) && q!='n' && q!='N') // %c前的空格为缓冲区
{
printf("请选择难易程度:简单(0)、中等(1)、困难(2) \n");
printf("在此输入难度:");
scanf("%d",&choice);
switch(choice)//
{
case 0:
initialData();
break;
case 1:
initialData();
break;
case 2:
initialData();
break;
}
while(1)
{
system("cls"); //清屏函数,由stdlib库调用
initialMap();
if(!boxs) //当箱子数为0时,break
{
break;
}
direction = getch();
switch(direction) //由w, a, s, d控制移动方向
{
case 'w':
moveUp();
break;
case 'a':
moveLeft();
break;
case 's':
moveDown();
break;
case 'd':
moveRight();
break;
}
}
printf("游戏胜利!奥利给!!\n");
printf("想要继续下一关吗?(y/n)\n"); //yes or no
}
printf("游戏结束,谢谢使用。\n");
return 0;
}
代码实现效果图
好啦,注释最详细的推箱子代码到此就已经结束啦(手动狗头),如果读者小伙伴们有不懂的方面或者有更好的创意和建议,可以在评论区留下您的宝贵意见或者私信我,我们一起学习,一起解决,一起进步。(看到这了,留个赞再走呗~)