一个不难的期末设计--推箱子游戏

本程序开发环境为Visual Studio 2022,全代码+资源可免费下载,见主页。

推箱子小游戏是一款经典的益智游戏,它的目标是在二维网格中移动箱子,将其推至指定位置。游戏通常包含玩家、箱子、目标位置和墙壁等元素。玩家可以通过键盘控制,在地图上向上、下、左、右移动。箱子可以被推动,但不能拉动,并且一次只能推动一个箱子。如果箱子前面的位置是空地或目标位置,就可以推动箱子向前移动一格。游戏的目标是将所有箱子推至目标位置,一旦所有箱子都被推到位,游戏即告胜利。

推箱子小游戏的基本规则是玩家需要在二维地图上推动箱子,将其推至指定位置。游戏通常会有多个关卡,每个关卡都有不同的地图布局和目标位置。玩家可以通过键盘控制玩家的移动方向,推动箱子,直到所有的箱子都被推至目标位置,即可通关。

地图是推箱子游戏的核心部分,它决定了游戏的难易程度和玩法的多样性。地图设计需要考虑箱子的数量、位置、目标位置以及障碍物的分布。地图可以是简单的单层平面,也可以是复杂的迷宫式结构,甚至是多层次的结构。地图的设计应该能够适应不同玩家的技能水平,从初级到高级,逐步提升游戏的难度。

推箱子游戏的交互设计主要是指玩家如何与游戏进行互动,包括玩家的移动方式、推动箱子的方式、输入设备的响应等。良好的交互设计可以使玩家更容易理解和掌握游戏规则,提高游戏的乐趣和可玩性。

在技术实现方面,推箱子游戏需要使用合适的数据结构和算法。常用的数据结构有二维数组、栈、队列等,它们分别用于存储地图状态、管理玩家的移动顺序和处理任务等。此外,还需要考虑游戏的性能优化,比如地图的预处理、状态的压缩存储等。

地图的读取:从文件中读取当前关卡的地图数据,并初始化二维数组map。同时,根据地图数据计算目的地的数量和位置,存储在Dests结构体中。

//读取关卡
void LoadLevel() {
	ifstream ifs;
	char tmp[10];
	ifs.open("./level/level.txt", ios::in);
	while (ifs >> tmp) {}
	level = atoi(tmp);
	ifs.close();
}

//写入关卡
void WriteLevel(int a) {
	ofstream ofs;
	char tmp[20];
    sprintf(tmp, "%d", a);
	ofs.open("./level/level.txt", ios::out);
	ofs << tmp<< endl;
	ofs.close();
}

Map::Map() {
	ifstream ifs;
	char str[20];
	sprintf(str, "./level/%d_map.txt", level);
	ifs.open(str, ios::in);
	int i = 0;
	while (ifs >> this->map[i]) {
		i++;
	}
	ifs.close();
	for (int i = 0; i < H / SIZE; i++) {
		for (int j = 0; j < W / SIZE; j++) {
			if (this->map[i][j] == '4') {
				d.num++;
				d.dest[d.num - 1].x = j * SIZE;
				d.dest[d.num - 1].y = i * SIZE;
			}
		}
	}
}

绘制地图:包括背景、墙体、目的地等元素,使用EasyX库的图形函数。

void Map::Draw() {
	IMAGE bk;
	loadimage(&bk, "./bk.jpg", W, H);
	putimage(0, 0, &bk);
	for (int i = 0; i < H / SIZE; i++) {
		for (int j = 0; j < W / SIZE; j++) {
			int x = j * SIZE;
			int y = i * SIZE;
			//空地
			if (this->map[i][j] == SPACE) {
				setfillcolor(RGB(210, 210, 210));
				fillrectangle(x, y, (x + SIZE), (y + SIZE));
			}
			//墙体
			if (this->map[i][j] == WALL) {
				IMAGE a;
				loadimage(&a, "./wall.png", SIZE, SIZE);
				putimage(x, y, &a);
			}
			//目的地
			if (this->map[i][j] == DEST) {
				setfillcolor(RGB(210, 210, 210));
				fillrectangle(x, y, (x + SIZE), (y + SIZE));
				IMAGE a;
				loadimage(&a, "./dest.png", SIZE, SIZE);
				drawImg(x, y, &a);
				//调用"tool.h"头文件当中的接口实现透明贴图
			}
		}
	}
}

键盘输入处理:通过GetAsyncKeyState函数检测用户输入的方向键,然后更新角色和箱子的位置。如果角色前方有箱子,会尝试推动箱子,同时检查箱子后面是否有墙体或另一个箱子,以防止箱子重叠或推不动。

//获取人物在二维数组中的坐标
int j = this->x / SIZE;
int i = this->y / SIZE;
//用来判断前面是否有箱子
int status = 0;
//按下移动键
if (GetAsyncKeyState('W')) {	
	for(int n = 0; n < b.num; n++) {
		//如果前面有箱子
		if (b.box[n].x == this->x && b.box[n].y == this->y - SIZE) {
			status = 1;
			//如果箱子后面不靠墙也不靠箱子
			if (m.map[i-2][j] != WALL&&!this->IsBox(b,b.box[n].x,b.box[n].y-SIZE)) {
				b.box[n].y -= SIZE;
				this->y -= SIZE;
			}
		}
	}
	//空地移动
	if ((m.map[i - 1][j] == SPACE || m.map[i - 1][j] == DEST)&&(status!=1)) {
		this->y -= SIZE;
	}
	return;
}

判断游戏是否胜利:遍历所有箱子和目的地,检查所有箱子是否都在对应的目的地上。

bool Box::IsWin(Map& m) {
	int count = 0;
	for (int i = 0; i < d.num; i++) {
		for (int j = 0; j < this->num; j++) {
			if (this->box[j].x == d.dest[i].x && this->box[j].y == d.dest[i].y) {
				count++;
			}
		}
	}
	if (count == d.num) {
		return true;
	}
	return false;
}

运行图:

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值