前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C语言控制台界面实现推箱子游戏

C语言控制台界面实现推箱子游戏

原创
作者头像
晨星成焰
修改2024-05-07 12:39:50
972
修改2024-05-07 12:39:50
举报

游戏目标

实现一个基本的推箱子游戏,包括地图初始化、显示、玩家和箱子的移动逻辑,以及游戏循环。通过键盘控制玩家可以移动玩家和箱子,游戏的目标是将所有箱子推到目标位置。

本游戏参考地图


初始化

定义颜色宏

代码语言:cpp
复制
#define green "\033[42;31m  \033[0m" 
#define red "\033[41;31m  \033[0m"//红色
#define black "\033[40;31m  \033[0m"//黑色
#define yellow "\033[43;37m  \033[0m"
#define blue "\033[44;37m  \033[0m"
#define pink "\033[45;37m  \033[0m"
#define l_blue "\033[46;37m  \033[0m"
#define white "\033[47;37m  \033[0m"

//初始化渲染颜色类型
//0路 1墙 2目的地 3箱子 4玩家 5箱子目的地 6玩家目的地 7背景
#define bg_color white
#define wall_color    yellow
#define space_color   green  //"\033[42;31m  \033[0m"
#define box_color    black
#define target_color    pink   //"\033[43;31m  \033[0m"
#define self_color  blue//"\033[46;31m  \033[0m"浅蓝色
#define boxTarget_color red
#define selfTarget_color l_blue

使用ANSI转义序列定义了多种颜色宏,用于在控制台输出时改变文本的颜色。这些宏通过\033[后跟颜色代码来设置颜色,然后\033[0m用于重置颜色。

粗略参考如下

地图因为只做了一关的缘故,所以只有一个maps1如果以后做多个关卡或者想存入数据库,可以改成三维数组的形式例如maps[index][mapX][mapY]

定义地图

代码语言:cpp
复制
#define map1X 10
#define map1Y 10

int maps1[map1X][map1Y] = 
{
	{7,1,1,1,1,1,1,7,7,7},
	{7,1,2,0,2,2,1,7,7,7},
	{7,1,2,0,3,2,1,7,7,7},
	{1,1,1,0,0,3,1,1,7,7},
	{1,0,3,0,0,3,0,1,7,7},
	{1,0,1,3,1,1,0,1,7,7},
	{1,0,0,0,4,0,0,1,7,7},
	{1,1,1,1,1,1,1,1,7,7},
	{7,7,7,7,7,7,7,7,7,7},
	{7,7,7,7,7,7,7,7,7,7}
};


void maps_Init(int map[][map1Y]) {
	// 使用memcpy复制maps1的内容到map
	//TODO加一个该关卡参数,通过不同的关卡值初始化不同的地图
	int maps1[map1X][map1Y] =
	{
	{7,1,1,1,1,1,1,7,7,7},
	{7,1,2,0,2,2,1,7,7,7},
	{7,1,2,0,3,2,1,7,7,7},
	{1,1,1,0,0,3,1,1,7,7},
	{1,0,3,0,0,3,0,1,7,7},
	{1,0,1,3,1,1,0,1,7,7},
	{1,0,0,0,4,0,0,1,7,7},
	{1,1,1,1,1,1,1,1,7,7},
	{7,7,7,7,7,7,7,7,7,7},
	{7,7,7,7,7,7,7,7,7,7}
	};

	memcpy(map, maps1, map1X * map1Y * sizeof(int));
}

显示和移动

显示地图

maps_Show函数负责显示当前的地图状态。它首先清空控制台,然后遍历地图数组,对每个元素根据其值打印相应的颜色和符号。

在遍历过程中,如果发现有箱子没有被推到目标位置,就设置isWin为0,表示游戏未赢。

代码语言:cpp
复制
void maps_Show() {
	printf("\033[H\033[2J");
	int isWin = 1;
	for (int i = 0; i < map1X; i++) {
		for (int j = 0; j < map1Y; j++) {
			switch (maps1[i][j])
			{
			case 0: {
				printf(space_color);
				break;
			}
			case 1: {
				printf(wall_color);
				break;
			}
			case 2: {
				printf(target_color);
				break;
			}
			case 3: {
				printf(box_color);
				break;
			}
			case 4: {
				printf(self_color);
				break;
			}
			case 5: {
				printf(boxTarget_color);
				break;
			}
			case 6: {
				printf(selfTarget_color);
				break;
			}
			case 7: {
				printf(bg_color);
				break;
			}
			default:
				break;
			}
		}
		printf("\n");
	}

	for (int i = 0; i < map1X; i++) {
		for (int j = 0; j < map1Y; j++) {
			if (maps1[i][j] == 3) {
				isWin = 0;
				break;
			}
		}
		if (!isWin) {
			break;
		}
	}
	if (isWin) {
		printf("\033[H\033[2J");
		printf("#####宝宝,你好厉害#####\n");
		Sleep(5000);
		maps_Init(maps1);
	}
}

移动玩家和箱子

moveP函数处理玩家的移动操作。根据用户的键盘输入(w/a/s/d),更新玩家的位置,并尝试将箱子移动到目标位置。

如果玩家或箱子移动到目标位置,会更新地图中的相应元素。

代码语言:cpp
复制
void moveP() 
{
	//获取玩家坐标
	int pX = 0, pY = 0;
	for (pX = 0; pX < map1X; pX++) {
		for (pY = 0; pY < map1Y; pY++) {
			if (maps1[pX][pY] == 4 || maps1[pX][pY] == 6) {
				break;
			}
		}
		if (maps1[pX][pY] == 4 || maps1[pX][pY] == 6) {
			break;
		}
	}

	switch (_getch())
	{
	case 'w':
	case 'W':
		if (maps1[pX - 1][pY] == 0 || maps1[pX - 1][pY] == 2)
		{
			maps1[pX - 1][pY] += 4; // 玩家移动到上方
			maps1[pX][pY] -= 4; // 玩家消失在原位置
		}
		else if (maps1[pX - 1][pY] == 3 || maps1[pX - 1][pY] == 3 + 2) // BOX + DEST
		{
			if (maps1[pX - 2][pY] == 0 || maps1[pX - 2][pY] == 2)
			{
				maps1[pX - 2][pY] += 3; // BOX移动到上方
				maps1[pX - 1][pY] = maps1[pX - 1][pY] - 3 + 4; // BOX + PLAYER
				maps1[pX][pY] -= 4; // 玩家消失在原来位置
			}
		}
		break;
	case 'a':
	case 'A':
		if (maps1[pX][pY - 1] == 0 || maps1[pX][pY - 1] == 2)
		{
			maps1[pX][pY - 1] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX][pY - 1] == 3 || maps1[pX][pY - 1] == 3 + 2) 
		{
			if (maps1[pX][pY - 2] == 0 || maps1[pX][pY - 2] == 2)
			{
				maps1[pX][pY - 2] += 3; 
				maps1[pX][pY - 1] = maps1[pX][pY - 1] - 3 + 4; 
				maps1[pX][pY] -= 4; 
			}
		}
		break;
	case's':
	case'S':
		if (maps1[pX + 1][pY] == 0 || maps1[pX + 1][pY] == 2)
		{
			maps1[pX + 1][pY] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX + 1][pY] == 3 || maps1[pX + 1][pY] == 3 + 2) 
		{
			if (maps1[pX + 2][pY] == 0 || maps1[pX + 2][pY] == 2)
			{
				maps1[pX + 2][pY] += 3; 
				maps1[pX + 1][pY] = maps1[pX + 1][pY] - 3 + 4;
				maps1[pX][pY] -= 4; 
			}
		}

		break;
	case'd':
	case'D':
		if (maps1[pX][pY + 1] == 0 || maps1[pX][pY + 1] == 2)
		{
			maps1[pX][pY + 1] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX][pY + 1] == 3 || maps1[pX][pY + 1] == 3 + 2) 
		{
			if (maps1[pX][pY + 2] == 0 || maps1[pX][pY + 2] == 2)
			{
				maps1[pX][pY + 2] += 3; 
				maps1[pX][pY + 1] = maps1[pX][pY + 1] - 3 + 4; 
				maps1[pX][pY] -= 4; 
			}
		}
		break;
	case 'r':
	case 'R': 
	{
		maps_Init(maps1);
	}
	default:
		break;
	}

}

游戏循环和主函数

main函数首先隐藏光标(printf("\033[?25l")),然后调用pushBoxStart_Init启动游戏。

pushBoxStart_Init函数启动游戏,首先调用maps_Init初始化地图,然后显示地图和游戏规则,进入游戏循环。

在游戏循环中,调用moveP处理玩家的移动操作,然后调用maps_Show更新地图显示。

以后可以在Start_Init里加入选关卡菜单,并且定义一个变量用来获取关卡值通过这个变量改变初始化的地图

代码语言:cpp
复制
//TODO关卡选择菜单
void pushBoxStart_Init() {
	maps_Init(maps1);
	maps_Show();
	printf(" **** **** **** **** **** **** **** **** \n");
	printf(" *                                     * \n");
	printf(" *     这是一个推箱子游戏              * \n");
	printf(" *     按wasd移动                      * \n");
	printf(" *     按r重置地图                     * \n");
	printf(" *     按q退出游戏                     * \n");
	printf(" *     黑色是箱子                      * \n");
	printf(" *     紫色是目的地                    * \n");
	printf(" *     蓝色是玩家                      * \n");
	printf(" *     绿色是路                        * \n");
	printf(" **** **** **** **** **** **** **** **** \n");
	while (1) {
		moveP();
		maps_Show();
	}
}

int main() {
	printf("\033[?25l");
	pushBoxStart_Init();

	return 0;
}

所有代码

代码语言:c
复制
#include<Windows.h>
#include<stdio.h>
#include<conio.h>

#define green "\033[42;31m  \033[0m" 
#define red "\033[41;31m  \033[0m"//红色
#define black "\033[40;31m  \033[0m"//黑色
#define yellow "\033[43;37m  \033[0m"
#define blue "\033[44;37m  \033[0m"
#define pink "\033[45;37m  \033[0m"
#define l_blue "\033[46;37m  \033[0m"
#define white "\033[47;37m  \033[0m"

//初始化渲染颜色类型
//0路 1墙 2目的地 3箱子 4玩家 5箱子目的地 6玩家目的地 7背景
#define bg_color white
#define wall_color    yellow
#define space_color   green  //"\033[42;31m  \033[0m"
#define box_color    black
#define target_color    pink   //"\033[43;31m  \033[0m"
#define self_color  blue//"\033[46;31m  \033[0m"浅蓝色
#define boxTarget_color red
#define selfTarget_color l_blue

#define map1X 10
#define map1Y 10

int maps1[map1X][map1Y] = 
{
	{7,1,1,1,1,1,1,7,7,7},
	{7,1,2,0,2,2,1,7,7,7},
	{7,1,2,0,3,2,1,7,7,7},
	{1,1,1,0,0,3,1,1,7,7},
	{1,0,3,0,0,3,0,1,7,7},
	{1,0,1,3,1,1,0,1,7,7},
	{1,0,0,0,4,0,0,1,7,7},
	{1,1,1,1,1,1,1,1,7,7},
	{7,7,7,7,7,7,7,7,7,7},
	{7,7,7,7,7,7,7,7,7,7}
};

void maps_Init(int map[][map1Y]) {
	// 使用memcpy复制maps1的内容到map
	//TODO加一个该关卡参数,通过不同的关卡值初始化不同的地图
	int maps1[map1X][map1Y] =
	{
	{7,1,1,1,1,1,1,7,7,7},
	{7,1,2,0,2,2,1,7,7,7},
	{7,1,2,0,3,2,1,7,7,7},
	{1,1,1,0,0,3,1,1,7,7},
	{1,0,3,0,0,3,0,1,7,7},
	{1,0,1,3,1,1,0,1,7,7},
	{1,0,0,0,4,0,0,1,7,7},
	{1,1,1,1,1,1,1,1,7,7},
	{7,7,7,7,7,7,7,7,7,7},
	{7,7,7,7,7,7,7,7,7,7}
	};

	memcpy(map, maps1, map1X * map1Y * sizeof(int));
}

void maps_Show() {
	printf("\033[H\033[2J");
	int isWin = 1;
	for (int i = 0; i < map1X; i++) {
		for (int j = 0; j < map1Y; j++) {
			switch (maps1[i][j])
			{
			case 0: {
				printf(space_color);
				break;
			}
			case 1: {
				printf(wall_color);
				break;
			}
			case 2: {
				printf(target_color);
				break;
			}
			case 3: {
				printf(box_color);
				break;
			}
			case 4: {
				printf(self_color);
				break;
			}
			case 5: {
				printf(boxTarget_color);
				break;
			}
			case 6: {
				printf(selfTarget_color);
				break;
			}
			case 7: {
				printf(bg_color);
				break;
			}
			default:
				break;
			}
		}
		printf("\n");
	}

	for (int i = 0; i < map1X; i++) {
		for (int j = 0; j < map1Y; j++) {
			if (maps1[i][j] == 3) {
				isWin = 0;
				break;
			}
		}
		if (!isWin) {
			break;
		}
	}
	if (isWin) {
		printf("\033[H\033[2J");
		printf("#####宝宝,你好厉害#####\n");
		Sleep(5000);
		maps_Init(maps1);
	}
}

void moveP() 
{
	//获取玩家坐标
	int pX = 0, pY = 0;
	for (pX = 0; pX < map1X; pX++) {
		for (pY = 0; pY < map1Y; pY++) {
			if (maps1[pX][pY] == 4 || maps1[pX][pY] == 6) {
				break;
			}
		}
		if (maps1[pX][pY] == 4 || maps1[pX][pY] == 6) {
			break;
		}
	}

	switch (_getch())
	{
	case 'w':
	case 'W':
		if (maps1[pX - 1][pY] == 0 || maps1[pX - 1][pY] == 2)
		{
			maps1[pX - 1][pY] += 4; // 玩家移动到上方
			maps1[pX][pY] -= 4; // 玩家消失在原位置
		}
		else if (maps1[pX - 1][pY] == 3 || maps1[pX - 1][pY] == 3 + 2) // BOX + DEST
		{
			if (maps1[pX - 2][pY] == 0 || maps1[pX - 2][pY] == 2)
			{
				maps1[pX - 2][pY] += 3; // BOX移动到上方
				maps1[pX - 1][pY] = maps1[pX - 1][pY] - 3 + 4; // BOX + PLAYER
				maps1[pX][pY] -= 4; // 玩家消失在原来位置
			}
		}
		break;
	case 'a':
	case 'A':
		if (maps1[pX][pY - 1] == 0 || maps1[pX][pY - 1] == 2)
		{
			maps1[pX][pY - 1] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX][pY - 1] == 3 || maps1[pX][pY - 1] == 3 + 2) 
		{
			if (maps1[pX][pY - 2] == 0 || maps1[pX][pY - 2] == 2)
			{
				maps1[pX][pY - 2] += 3; 
				maps1[pX][pY - 1] = maps1[pX][pY - 1] - 3 + 4; 
				maps1[pX][pY] -= 4; 
			}
		}
		break;
	case's':
	case'S':
		if (maps1[pX + 1][pY] == 0 || maps1[pX + 1][pY] == 2)
		{
			maps1[pX + 1][pY] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX + 1][pY] == 3 || maps1[pX + 1][pY] == 3 + 2) 
		{
			if (maps1[pX + 2][pY] == 0 || maps1[pX + 2][pY] == 2)
			{
				maps1[pX + 2][pY] += 3; 
				maps1[pX + 1][pY] = maps1[pX + 1][pY] - 3 + 4;
				maps1[pX][pY] -= 4; 
			}
		}

		break;
	case'd':
	case'D':
		if (maps1[pX][pY + 1] == 0 || maps1[pX][pY + 1] == 2)
		{
			maps1[pX][pY + 1] += 4; 
			maps1[pX][pY] -= 4; 
		}
		else if (maps1[pX][pY + 1] == 3 || maps1[pX][pY + 1] == 3 + 2) 
		{
			if (maps1[pX][pY + 2] == 0 || maps1[pX][pY + 2] == 2)
			{
				maps1[pX][pY + 2] += 3; 
				maps1[pX][pY + 1] = maps1[pX][pY + 1] - 3 + 4; 
				maps1[pX][pY] -= 4; 
			}
		}
		break;
	case 'r':
	case 'R': 
	{
		maps_Init(maps1);
	}
	default:
		break;
	}

}

//TODO关卡选择菜单
void pushBoxStart_Init() {
	maps_Init(maps1);
	maps_Show();
	printf(" **** **** **** **** **** **** **** **** \n");
	printf(" *                                     * \n");
	printf(" *     这是一个推箱子游戏              * \n");
	printf(" *     按wasd移动                      * \n");
	printf(" *     按r重置地图                     * \n");
	printf(" *     按q退出游戏                     * \n");
	printf(" *     黑色是箱子                      * \n");
	printf(" *     紫色是目的地                    * \n");
	printf(" *     蓝色是玩家                      * \n");
	printf(" *     绿色是路                        * \n");
	printf(" **** **** **** **** **** **** **** **** \n");
	while (1) {
		moveP();
		maps_Show();
	}
}

int main() {
	printf("\033[?25l");
	pushBoxStart_Init();

	return 0;
}

运行截图


未来展望

引入图形库,加颜色渲染改成图片渲染,加入多个关卡选项打包成.exe文件发给朋友游玩

参考文章

C语言实现推箱子 (数据库连接+项目打包发布)


我正在参与2024腾讯技术创作特训营最新征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 游戏目标
    • 初始化
      • 定义颜色宏
      • 定义地图
    • 显示和移动
      • 显示地图
      • 移动玩家和箱子
    • 游戏循环和主函数
    • 所有代码
      • 运行截图
      • 未来展望
      • 参考文章
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档