推箱子游戏详解
【摘要】 🎈 作者:Linux猿
🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!
🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬
🎈 作者:Linux猿
🎈 简介:CSDN博客专家🏆,华为云享专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!
推箱子游戏大家应该非常熟悉,非常经典的一款游戏,本文来详细讲解下推箱子游戏的制作过程,赶紧来看下吧!
首先,看下效果图:
图1 游戏过程
一、界面设计
1.1 主界面
主界面如下所示:
主界面主要包括开始游戏和退出游戏。
1.2 游戏界面
游戏界面是通过读取文件中的数据,然后显示到终端界面,如下所示:
包括的各个函数有:
void showMap(); //输出地图
void move(char ch); //移动
void hideCursor(); //隐藏光标
void getCoord(int x, int y);//光标定位
void menu(); //选择界面
void readGameData(); //读取游戏数据
void sokoban(); //游戏主要流程
包含的数据结构有:
struct Location {
int x, y;
}target[NUM*NUM];
char map[NUM][NUM];
其中,target[NUM*NUM] 用于存储目标位置的坐标,map[NUM][NUM]用于存储地图。
主流程如下所示:
//游戏主流程
void sokoban()
{
showMap(); //展示地图
hideCursor(); //隐藏光标
while (true) {
if(_kbhit()) {
char ch = _getch(); //获取用户输入
switch (ch) {
case 'w': //上
move(ch); break;
case 's': //下
move(ch); break;
case 'a': //左
move(ch); break;
case 'd': //右
move(ch); break;
}
}
Sleep(10);
}
}
设计思路如下:
1. 读取游戏地图数据;
2. 等待用户输入;
3. 根据用户输入移动人;
4. 判断是否移动成功;
5. 循环 2 ~ 4,一直到游戏成功;
三、源代码
源码如下,可直接运行。
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <stdbool.h>
#define GAMEDATAPATH "data.txt"
#define NUM 200
int lx = 10, ly = 17;
char map[NUM][NUM];
int numTarget = 0;
int nx, ny, sx, sy, mb, n=1;
struct Location {
int x, y;
}target[NUM*NUM];
void showMap(); //输出地图
void move(char ch); //移动
void hideCursor(); //隐藏光标
void getCoord(int x, int y);//光标定位
void menu(); //选择界面
void readGameData(); //读取游戏数据
void sokoban(); //游戏主要流程
//隐藏光标
void hideCursor()
{
CONSOLE_CURSOR_INFO cursor= { 1, 0 };
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor);
}
//设置颜色
void color(int a)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), a);
}
//光标重定位,用于在光标处输出
void getCoord(int x, int y)
{
COORD pos = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
void checkTargetGraph() {
int i;
for(i = 0; i < numTarget; ++i) {
int x = target[i].x;
int y = target[i].y;
if(map[x][y] == '2') {
getCoord((y+ly)*2, x+lx); color(4); printf("★"); color(7);
}
}
}
bool checkSuccess() {
int i;
for(i = 0; i < numTarget; ++i) {
int x = target[i].x;
int y = target[i].y;
if(map[x][y] != 'B') {
return false;
}
}
return true;
}
//从文件中读取游戏地图数据
void readGameData()
{
int i, j;
FILE* fp = fopen(GAMEDATAPATH, "r");
if (fp == NULL) {
printf("Error: Failed to read data!");
return;
}
//读取行和列
fscanf(fp, "%d %d %d %d", &nx, &ny, &sx, &sy);
//读取数据
for(i = 0; i < nx; ++i) {
fscanf(fp, "%s", map[i]);
}
for(i = 0; i < nx; ++i) {
for(j = 0; j < ny; ++j) {
if(map[i][j] == 'C') {
target[numTarget].x = i;
target[numTarget++].y = j;
}
}
}
fclose(fp);
}
//输出游戏地图
void showMap()
{
system("cls"); //清屏
int i, j;
for(i = 0; i < nx; ++i) {
for(j = 0; j < ny; ++j){
getCoord((j+ly)*2, i+lx);
if(map[i][j] == '1') {
color(52); printf("■");
} else if(map[i][j] == '2') {
printf(" ");
} else if(map[i][j] == 'A') {
color(1); printf("♀");
} else if(map[i][j] == 'B') {
color(6); printf("■");
} else if(map[i][j] == 'C') {
color(4); printf("★");
}
color(7);
}
}
}
//主界面
int main()
{
system("chcp 65001"); //语言支持
system("mode con cols=90 lines=30");//设置终端大小
system("cls");
menu();//菜单
sokoban(); //主要流程
return 0;
}
void menu()//主流程
{
system("cls"); //清屏
getCoord(39, 8); color(9); printf("推箱子游戏"); color(7);
getCoord(38, 12); color(9); printf("1. 开始游戏"); color(7);
getCoord(38, 14); color(9); printf("2. 退出游戏"); color(7);
hideCursor();
while(true) {
char chn=_getch();//选择
if(chn == '1') {
readGameData(); //读取游戏数据
break;
} else if (chn == '2') { //退出游戏
system("cls");
getCoord(39, 8); printf("推箱子游戏");
getCoord(38, 15); printf("欢迎下次光临");
Sleep(3000);
exit(1);
} else {
getCoord(39, 18); printf("输入错误!");
Sleep(1000);
getCoord(39, 18); printf(" ");
}
}
}
void move(char ch)
{
if(ch == 'd') {
if(sy + 1 < ny && map[sx][sy+1] != '1') {// 人右边没有超出方框,且右边不是墙
if(map[sx][sy+1] == '2' || map[sx][sy+1] == 'C') {//是空格或目标直接走过去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2+2, sx+lx); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx][sy+1] = 'A';
sy = sy + 1;
} else if(map[sx][sy+1] == 'B' && sy + 2 < ny && (map[sx][sy+2] == '2' || map[sx][sy+2] == 'C')) {//人 箱子 空格
getCoord((sy+ly)*2+4, sx+lx); printf(" ");
getCoord((sy+ly)*2+4, sx+lx); color(6); printf("■"); color(7);
getCoord((sy+ly)*2+2, sx+lx); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx][sy+2] = 'B';
map[sx][sy+1] = 'A';
map[sx][sy] = '2';
sy = sy + 1;
}
}
} else if(ch == 'a') {
if(sy - 1 >= 0 && map[sx][sy-1] != '1') {// 人左边没有超出方框,且左边不是墙
if(map[sx][sy-1] == '2' || map[sx][sy-1] == 'C') {//是空格直接走过去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2-2, sx+lx); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx][sy-1] = 'A';
sy = sy - 1;
} else if(map[sx][sy-1] == 'B' && sy - 2 >= 0 && (map[sx][sy-2] == '2' || map[sx][sy-2] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2-4, sx+lx); printf(" ");
getCoord((sy+ly)*2-4, sx+lx); color(6); printf("■"); color(7);
getCoord((sy+ly)*2-2, sx+lx); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx][sy-2] = 'B';
map[sx][sy-1] = 'A';
map[sx][sy] = '2';
sy = sy - 1;
}
}
} else if(ch =='w') {
if(sx - 1 >= 0 && map[sx-1][sy] != '1') {// 人上面没有超出方框,且上面不是墙
if(map[sx-1][sy] == '2' || map[sx-1][sy] == 'C') {//是空格直接走过去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2, sx+lx-1); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx-1][sy] = 'A';
sx = sx - 1;
} else if(map[sx-1][sy] == 'B' && sx - 2 >= 0 && (map[sx-2][sy] == '2' || map[sx-2][sy] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2, sx+lx-2); printf(" ");
getCoord((sy+ly)*2, sx+lx-2); color(6); printf("■"); color(7);
getCoord((sy+ly)*2, sx+lx-1); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx-2][sy] = 'B';
map[sx-1][sy] = 'A';
map[sx][sy] = '2';
sx = sx - 1;
}
}
} else if(ch =='s') {
if(sx + 1 < nx && map[sx+1][sy] != '1') {// 人上面没有超出方框,且上面不是墙
if(map[sx+1][sy] == '2' || map[sx+1][sy] == 'C') {//是空格直接走过去
getCoord((sy+ly)*2, sx+lx); printf(" ");
getCoord((sy+ly)*2, sx+lx+1); color(1); printf("♀"); color(7);
map[sx][sy] = '2';
map[sx+1][sy] = 'A';
sx = sx + 1;
} else if(map[sx+1][sy] == 'B' && sx + 2 >= 0 && (map[sx+2][sy] == '2' || map[sx+2][sy] == 'C')) {//空格 箱子 人
getCoord((sy+ly)*2, sx+lx+2); printf(" ");
getCoord((sy+ly)*2, sx+lx+2); color(6); printf("■"); color(7);
getCoord((sy+ly)*2, sx+lx+1); color(1); printf("♀"); color(7);
getCoord((sy+ly)*2, sx+lx); printf(" ");
map[sx+2][sy] = 'B';
map[sx+1][sy] = 'A';
map[sx][sy] = '2';
sx = sx + 1;
}
}
}
checkTargetGraph(); //显示目标,防止覆盖
bool flag = checkSuccess(); //检查是否成功
if(flag) {
getCoord(38, 19); color(4); printf("Success\n"); color(7);
}
}
//游戏主流程
void sokoban()
{
showMap(); //展示地图
hideCursor(); //隐藏光标
while (true) {
if(_kbhit()) {
char ch = _getch(); //获取用户输入
switch (ch) {
case 'w': //上
move(ch); break;
case 's': //下
move(ch); break;
case 'a': //左
move(ch); break;
case 'd': //右
move(ch); break;
}
}
Sleep(10);
}
}
data.txt文件游戏数据如下所示,放到和源文件同目录下。
7 10 3 2
1111111111
1122222111
11B1112221
12A2B22B21
12CC12B211
11CC122211
1111111111
四、总结
推箱子游戏的重点在于人的移动,人可以向上下左右四个方向移动,需要判断人的前面的物体。游戏界面设计主要是根据用户的输入移动人,每次移动后判断是否成功。
🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬
推荐
华为开发者空间发布
让每位开发者拥有一台云主机
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)