当前位置: 首页 > article >正文

游戏设计:推箱子【easyx图形界面/c语言】

在之前写程序设计的大作业时,在哔哩哔哩上跟着一个视频的学习的成果【第一个练习的】

今天整理文件的时候看到的,就发出来一下【CSDN和B站都有详细教程】

不是大项目,只有两个界面

这个代码只有两百行不到,但通过这个把基本的运行逻辑什么的掌握了,然后写自己的完整的游戏设计


经典的推箱子玩法,玩家需要控制一个小人,将箱子推到指定的目标位置,直到通关

#include<graphics.h>
#include<conio.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650  //屏幕宽高

#define RATIO 50 //道具比例

#define START_X 100
#define START_Y 100

#define  LINE 9
#define COLUMN 12


//控制键上下左右,退出键
#define KEY_UP 'w'
#define KEY_DOWN 's'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_QUIT 'q'




//#define KEY_UNDO 'u' // 撤回键
//#define KEY_RESTART 'r' // 重玩键



#define isvalid(pos) (pos.x>=0 && pos.x<LINE && pos.y>=0 && pos.y<COLUMN)
//确保下标不会越界,移动的前提

enum _PROPS
{
	WALL,//墙0
	FLOOR,//地板1
	BOX_DES,//箱子目的地2
	MAN,//小人3
	BOX,//箱子4
	HIT,//箱子的正确位置5
	GameOver,//通关界面6
	ALL    //7数组个数
};
// 显高级枚举法,暂时不想改

typedef enum _PROPS PROPS;//定义别名

//游戏控制方向,枚举变量
enum _DIRECTION 
{
	UP,
	DOWN,
	LEFT,
	RIGHT,
};
typedef enum _DIRECTION DIRECTION;//用类型定义作简化

//0:墙 ,1:地板,2:目的地,3:小人,4:箱子,5:正确位置的箱子
int map[9][12] =
{
	{0,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,0,1,1,1,1,1,1,1,0,0},
	{0,1,4,1,0,2,1,0,2,1,0,0},
	{0,1,0,2,0,1,1,4,1,1,1,0},
	{0,1,1,1,0,3,1,1,1,4,1,0},
	{0,1,2,1,1,4,1,1,1,1,1,0},
	{0,1,0,0,1,0,1,1,0,0,1,0},
	{0,0,0,0,0,0,0,0,0,0,0,0},
};

IMAGE images[ALL];



struct _POS 
{
	int x;//小人所在的二维数组的行
	int y;//小人所在的二维数组的列
};
typedef struct _POS POS;//POS小人的坐标的数据类型

POS man;     //小人的实时位置,包含小人的坐标


//
void ChangeMap(POS* pos, PROPS prop)
{
	map[pos->x][pos->y] = prop;//位置  数组要改
	putimage(START_X + pos->y * RATIO, START_Y + pos->x * RATIO, &images[prop]);//视图

}
/********************
实现上下左右控制
输入:

输出
********************/


void GameControl(DIRECTION direct) //void没有返回值,方向类型定义变量
{
	POS next_pos = man;//小人下一个的位置,变量初始化
	POS	next_next_pos = man;//小人下下个的位置

	switch (direct) //switch判断方向
	{
	case UP:
		next_pos.x = man.x - 1;
		next_next_pos.x = man.x - 2;
		break;
	case DOWN:
		next_pos.x = man.x + 1;
		next_next_pos.x = man.x + 2;//上下行变,列不变
		break;
	case LEFT:
		next_pos.y = man.y - 1;
		next_next_pos.y = man.y - 2;
		break;
	case RIGHT:
		next_pos.y = man.y + 1;
		next_next_pos.y = man.y + 2;//左右列变
		break;
	}
	/**********
	在一个狭小的仓库中,要求把木箱放到指定的位置
	稍不小心就会出现箱子无法移动或者通道被堵住的情况
	***********/
	//逻辑判断,小人怎么走
	//如果小人前进一步是地板,则前进
	// 人到next_pos位置,原来的位置变成地板
	if (isvalid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR) 
	{
		ChangeMap(&next_pos, MAN);//
		ChangeMap(&man, FLOOR);//人原来的位置
		man = next_pos;//小人的实时位置
	}

	//如果人前进一步是   箱子  ,并且箱子前面next_next_pos是地板或者箱子目的地,则推着箱子走
	// 
	if (isvalid(next_pos) && map[next_pos.x][next_pos.y] == BOX)
	{
		//箱子前面是地板
		if (isvalid(next_next_pos) && map[next_next_pos.x][next_next_pos.y] == FLOOR)
		{
			ChangeMap(&next_next_pos,BOX);
			ChangeMap(&next_pos, MAN);
			ChangeMap(&man, FLOOR);
			man = next_pos;
		}//箱子前面是目的地
		else if (isvalid(next_next_pos) && map[next_next_pos.x][next_next_pos.y] == BOX_DES)
		{
			ChangeMap(&next_next_pos, HIT);//箱在目的地
			ChangeMap(&next_pos, MAN);
			ChangeMap(&man, FLOOR);
			man = next_pos;
		}
	}

}
bool IsGameover()
{
	for (int i = 0; i < LINE; i++) 
	{
		for (int j = 0; j < COLUMN; j++) 
		{
			if (map[i][j] == BOX_DES)
			{
				return false;
			}
		}
	}
	return true;
}


//游戏结束
void GameOverScene(IMAGE* bg)
{
	putimage(0, 0, bg);
	settextcolor(RED);
	RECT rec = { 0,0,SCREEN_WIDTH,SCREEN_HEIGHT };//跟屏幕同宽高
	settextstyle(80, 0, "楷体");
	drawtext("恭喜您成功通关", & rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

}




int main(void)
{
	//定义一个表示图片的变量
	IMAGE bg_img;
	initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);//屏幕宽高
	//定义一个表示图片的变量
	IMAGE gameoverscene;
	//设置成功背景
	loadimage(&gameoverscene, "GameOverScene.png", SCREEN_WIDTH, SCREEN_HEIGHT, true);//true表示图片自适应
	//设置背景
	loadimage(&bg_img, "beijing.png", SCREEN_WIDTH, SCREEN_HEIGHT, true);//true表示图片自适应
	putimage(0, 0, &bg_img);
	//物件图片
	loadimage(&images[0], "wall.png", RATIO, RATIO, true);//墙 
	loadimage(&images[1], "floor.png", RATIO, RATIO, true);//地板
	loadimage(&images[2], "des.png", RATIO, RATIO, true);//目的地
	loadimage(&images[3], "man.png", RATIO, RATIO, true);//小人
	loadimage(&images[4], "box.png", RATIO, RATIO, true);//箱子
	loadimage(&images[5], "box.png", RATIO, RATIO, true);//正确位置的箱子
	
	for (int i = 0;i < 9;i++)
	{
		for (int j = 0;j < 12;j++)
		{
			if (map[i][j] == MAN)
			{
				man.x = i;
				man.y = j;//x行,y列
			}//小人的位置
			putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
		}
	}


	bool quit = false;//游戏结束条件

	//热键控制
	do
	{
		if (_kbhit())      //_kbnit(),_grtch()关于按键的函数
		{//判断是否有按键,如果有按键按
			char ch = _getch();
			if (ch == KEY_UP)//w
			{
				GameControl(UP);//游戏控制
			}
			else if (ch == KEY_DOWN)//s
			{
				GameControl(DOWN);
			}
			else if (ch == KEY_LEFT)//a
			{
				GameControl(LEFT);
			}
			else if (ch == KEY_RIGHT)//d
			{
				GameControl(RIGHT);
			}
			else if (ch == KEY_QUIT) //q
			{
				quit = true;
			}
			else if (ch == KEY_QUIT) //q
			{
				quit = true;
			}
			if (IsGameover())//判断游戏是否结束,所有的2全没了
			{
				GameOverScene(& gameoverscene);
			}
		}
		Sleep(100);//100ms,0.1s
		//在没有按键的情况下让CPU休息一下,降低CPU率
	} while (quit == false);


	system("pause");
	return 0;


}

是一个简单的推箱子游戏的实现,使用了 graphics.h 库来进行图形显示。

功能简单明了。

1. 游戏地图的初始化

游戏地图是一个二维数组,包含墙壁、地板、箱子、目的地等不同的元素。通过 map 数组表示,不同的整数值代表不同的元素。

int map[9][12] = {
    {0,0,0,0,0,0,0,0,0,0,0,0},  // 0代表墙
    {0,1,0,1,1,1,1,1,1,1,0,0},  // 1代表地板
    {0,1,4,1,0,2,1,0,2,1,0,0},  // 4代表箱子,2代表目的地
    // ...
};
  • 0 表示墙壁
  • 1 表示地板
  • 2 表示箱子目的地
  • 3 表示小人
  • 4 表示箱子
  • 5 表示正确放置的箱子

2. 结构体与枚举类型

  • PROPS 枚举定义了不同的游戏元素类型(如墙、地板、箱子等)。

  • DIRECTION 枚举定义了小人的移动方向(上、下、左、右)。

  • POS 结构体用来表示位置,包含 xy 两个成员,分别表示二维数组的行列。

3. 游戏控制和移动逻辑

GameControl 函数是控制小人移动的核心。根据输入的方向(上下左右),更新小人的位置,并处理箱子的推送逻辑。具体逻辑如下:

  • 如果小人前进的方向是地板,则小人可以移动。

  • 如果小人前进的方向是箱子,且箱子后方是地板或目的地,箱子可以被推移。

4. 游戏结束判断

IsGameover 函数用来判断游戏是否结束,判断标准是所有目的地(BOX_DES)上是否都有箱子。

5. 图形显示

使用 putimage 函数显示图像,加载各类图像(如墙壁、地板、箱子等),并通过 ChangeMap 函数来更新游戏地图的显示。

6. 用户输入与游戏循环

游戏通过 _kbhit()_getch() 检测用户的按键输入。如果按下控制键(如 w, a, s, d),则调用 GameControl 函数进行相应的移动操作。如果按下退出键(q),则退出游戏。


把这些东西理解后就可以自己扩写改造了,

我最后的大作业就是基于最简单的推箱子游戏进行改动,增加其他的功能进行功能扩展

这里的图片来源于网络,可能按照自己的想法更改

完整文件我上传到这了,下载可以直接运行

游戏设计:推箱子【easyx图形界面/c语言】资源-CSDN文库

自己看用上面代码然后自己整加图片素材也可以正常运行

图像加载

游戏中的每个对象(如墙、地板、小人、箱子等)都通过图像来表示。我们使用loadimage函数将图像加载到内存,并通过图形界面显示出来。

loadimage(&images[0], "wall.png", RATIO, RATIO, true); // 加载墙壁图像
loadimage(&images[1], "floor.png", RATIO, RATIO, true); // 加载地板图像
loadimage(&images[2], "des.png", RATIO, RATIO, true);   // 加载目标图像
loadimage(&images[3], "man.png", RATIO, RATIO, true);    // 加载小人图像
loadimage(&images[4], "box.png", RATIO, RATIO, true);    // 加载箱子图像

“”里就是图片对应的图片路径

loadimage(&images[4], "box.png", RATIO, RATIO, true);

"box.png" 是图像文件的路径,它是一个名为 box.png 的图像文件。

图像文件可以是多种格式,比如 .png, .jpg 等,这里使用的是 .png 格式。box.png 应该是存放在程序的工作目录下,或者是通过相对/绝对路径进行访问。

这里是直接存储在代码所在的文件夹

如果想现有运行效果,针对导入图片的一些代码加入自己的图片路径即可
 


http://www.kler.cn/a/394509.html

相关文章:

  • 【RAG实战】Prompting vs. RAG vs. Finetuning: 如何选择LLM应用选择最佳方案
  • Day13 苍穹外卖项目 工作台功能实现、Apache POI、导出数据到Excel表格
  • LeetCode 209. 长度最小的子数组 (C++实现)
  • Java爬虫获取1688 item_search_img接口详细解析
  • 基于python+django的外卖点餐系统
  • Datawhale AI冬令营——Chat-悟空设计
  • AcWing 1097 池塘计数 flood fill bfs搜索
  • JFlash添加自定义MCU型号
  • 【汇编语言】包含多个段的程序(二)—— 将数据、代码、栈放入不同的段
  • 图像融合self
  • vscode远程连接+免密登录
  • 【Linux学习】【Ubuntu入门】1-3 ubuntu连接USB设备
  • IntelliJ+SpringBoot项目实战(七)--在SpringBoot中整合Redis
  • 职场中天天工作太累太无趣
  • 前端呈现效果:鱼眼相机城市环境图像分割
  • SQL语句执行的基本架构——数据库
  • Dify + Xinference:一站式本地 LLM 私有化部署和应用开发
  • 【C#设计模式(10)——装饰器模式(Decorator Pattern)】
  • 3D意识(3D Awareness)浅析
  • 《InsCode AI IDE:编程新时代的引领者》
  • 【Java】【Spring框架】【复习】1
  • RFC 2018 即《TCP Selective Acknowledgement Options》
  • 两大新兴开发语言大比拼:Move PK Rust
  • 自动驾驶仿真:软件在环(SIL)测试详解(精简版入门)
  • 华为云租户网络-用的是隧道技术
  • PC端微信多开