练手小项目---推箱子

项目需求

实现一款推箱子游戏,效果如下图所示,具体规则:

  1. 箱子只能推动而不能拉动;
  2. 如果箱子前一格是地板或箱子目的地,则可以推动一个箱子往前走一格,如果箱子已经在 箱子目的地则不能再推动;
  3. 推箱子的小人不能从箱子目的地上直接穿过;
  4. 注意不要把箱子推到死角上,不然就无法再推动它了;
  5. 所有箱子都成功推到箱子目的地,游戏结束,过关成功!
    在这里插入图片描述

项目资源显示

墙 地板 箱子目的地 小人 箱子 箱子命中目标
在这里插入图片描述

项目实现

说明:有关图像处理该项目使用的是easyX图形库

txz.h

#pragma once
using namespace std;

/*游戏窗口宽高设置*/
#define SCREEN_WIDTH 960
#define SCREEN_HEIGHT 768
/*游戏地图行列设置*/
#define LINE	9
#define COLUNM	12
/*游戏地图与窗口的偏移*/
#define START_X 100
#define START_Y 50
/*表示热键<上下左右与退出>*/
#define KEY_UP		'w'
#define KEY_LEFT	'a'
#define KEY_RIGHT	'd'
#define KEY_DOWN	's'
#define KEY_QUIT	'q'
#define isValid(pos)  pos.x >= 0 && pos.x < LINE && pos.y >= 0 && pos.y < COLUNM

/*枚举地图元素*/
enum _PROPS {
	WALL,	//墙0
	FLOOR,	//地板1
	BOX_DES,//箱子目的地2
	MAN,	//小人3       
	BOX,	//箱子4
	HIT,	//箱子命中目标5
	MAN_HIT,//小人击中目的地6
	ALL		//地图元素的总数
};
/*枚举小人方向控制*/
enum _DIRECTION {
	UP,		//上
	DOWN,	//下
	LEFT,	//左
	RIGHT	//右
};
/*定义一个全局地图数组(表示有ALL<6>个地图道具)*/
IMAGE images[ALL];

/*定义小人结构体<在地图中的位置>*/
struct _POS {
	int x;//表示小人的列坐标
	int y;//表示小人的行坐标
}man;

/*二维数组游戏地图*/
int map[LINE][COLUNM] = {
	{ 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, 1, 0, 1, 0, 0, 1, 1, 1, 0 },
	{ 0, 1, 0, 2, 0, 1, 1, 4, 1, 1, 1, 0 },
	{ 0, 1, 1, 1, 0, 3, 1, 1, 2, 4, 1, 0 },
	{ 0, 1, 2, 1, 1, 4, 1, 2, 2, 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 } };

/***************按键后地图道具的改变的函数*****************
*实现小人移动后道具的改变
*输入:line-地图数组的行下标
	  column-地图数组的列下标
	  prop-道具的类型
*输出:无
**********************************************************/
void changeMap(struct _POS* pos, enum _PROPS prop) {
	map[pos->x][pos->y] = prop;
	putimage(pos->y * 61 + START_X, pos->x * 61 + START_Y, &images[prop]);
}

/**************小人方向控制函数实现*************************
*实现游戏四个方向(上、下、左、右)的控制
* 输入: direct - 人前进方向
* 输出: 无
***********************************************************/
void gameControl(enum  _DIRECTION  direct)
{/*
	int x = man.x;
	int y = man.y;
	 if (direct == UP) //小人向上走
	{
		 if ((x-1)>=0&&map[x-1][y]==FLOOR) {
			 changeMap(x - 1, y, MAN);//小人前进一格
			 man.x = x - 1;			//小人位置坐标前进一格
			 changeMap(x, y, FLOOR);//人所在的位置为地板
		 }
	}
	else if(direct == DOWN)//小人向下走
	{
		 if ((x+1) <LINE && map[x +1][y] == FLOOR) {
			 changeMap(x +1, y, MAN);//小人后退一格
			 man.x = x + 1;			//小人位置坐标前进一格
			 changeMap(x, y, FLOOR);//人所在的位置为地板

		 }
	}
	else if (direct == LEFT)//小人向左走
	{
		 if ((y-1)>= 0 && map[x ][y-1] == FLOOR) {
			 changeMap(x , y-1, MAN);//小人左走一格
			 man.y = y- 1;			//小人位置坐标左走一格
			 changeMap(x, y, FLOOR);//人所在的位置为地板

		 }
	}
	else if (direct == RIGHT)//小人向右走
	{
		 if ((y+1)<= COLUNM && map[x ][y+1] == FLOOR)
		 {
			 changeMap(x , y+1, MAN);//小人右走一格
			 man.y = y +1;			//小人位置坐标右走一格
			 changeMap(x, y, FLOOR);//人所在的位置为地板
		 }
	}
	*/

	//优化后的小人热键控制
	struct _POS next_pos = man;		//小人前一格的道具		
	struct _POS next_next_pos = man;	//小人前两格的道具


	switch (direct)
	{
	case UP:
		//next_next_pos=next_next_pos-1
		next_pos.x--;
		//next_next_pos.x = next_next_pos.x - 2;
		next_next_pos.x -= 2;
		break;
	case DOWN:
		next_pos.x++;
		next_next_pos.x += 2;
		break;
	case LEFT:
		next_pos.y--;
		next_next_pos.y -= 2;
		break;
	case RIGHT:
		next_pos.y++;
		next_next_pos.y += 2;
		break;
	}
	//(一)小人前进方向为地板
	//if (next_pos.x >= 0 && next_pos.x < LINE && next_pos.y >= 0 && next_pos.y < COLUNM && map[next_pos.x][next_pos.y] == FLOOR) {
	if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR)
	{
		changeMap(&next_pos, MAN);
		changeMap(&man, FLOOR);
		man = next_pos;
	}
	//(二)小人前进方向为箱子
	else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX) {
		//小人前两格(箱子前面)为地板
		if (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 (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;
		}
	}
	//(三)小人前方是目的地
	else if (isValid(next_pos) && map[next_pos.x][next_pos.y] == BOX_DES) {
		//小人原位置前一格改为小人
		changeMap(&next_pos, MAN);
		//小人原位置改为地板
		changeMap(&man, FLOOR);
		man = next_pos;
		//小人所地图位置改为6
		map[man.y][man.x] = 6;
		if ( map[next_pos.x][next_pos.y] == FLOOR) {
			//小人原位置前一格改为小人
			changeMap(&next_pos, MAN);
			//小人原位置改为地板
			changeMap(&man, BOX_DES);
			man = next_pos;
			//map[][] = 5;

		}
	}

}


/**********************************************
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* true - 游戏结束 false - 游戏继续
**********************************************/
bool isGameOver()
{
	for (int i = 0; i < LINE; i++) {
		for (int j = 0; j < COLUNM; j++) {
			if (map[i][j] == BOX_DES) return false;
		}
	}
	return true;
}

/**********************************************
 *游戏结束场景,在玩家通关后显示
 *输入:
 * bg - 背景图片变量的指针
 *返回值: 无
 **********************************************/
void gameOverScene(IMAGE* bg)
{
	putimage(0, 0, bg);
	settextcolor(WHITE);
	RECT rec = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
	settextstyle(20, 0, _T("宋体"));
	drawtext(_T("恭喜您~ \n 您终于成为了一个合格的搬箱子老司机!"), &rec, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}

main.cpp

#include<Windows.h>
#include<string>
#include<iostream>
#include<graphics.h>
#include<conio.h>//获取热键头文件
#include"txz.h"

int main(void) {

	/**************地图场景初始化*************/
	//声明一个图片句柄
	IMAGE bg_img;
	//设置游戏场景
	initgraph(SCREEN_WIDTH, SCREEN_HEIGHT);
	//把图片加载到bg_img中并指明所加载的图片和图片的宽 高 是否拉升图片
	loadimage(&bg_img,"blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT,true);
	//把图片放在场景中(放在场景的左上角)
	putimage(0,0,&bg_img);

	/*************地图道具初始化**************/
	/*
	道具加载:   墙0   地板1      箱子目的地2  
				小人3   箱子4    箱子命中目标5
	*/
	//加载图片并指明图片宽与高的像素和是否拉升图片
	loadimage(&images[WALL], "wall_right.bmp",61,61, true);
	loadimage(&images[FLOOR], "floor.bmp",61, 61, true);
	loadimage(&images[BOX_DES], "des.bmp", 61, 61, true);
	loadimage(&images[MAN], "man.bmp", 61, 61, true);
	loadimage(&images[BOX], "box.bmp", 61, 61, true);
	loadimage(&images[HIT], "box.bmp", 61, 61, true);
	loadimage(&images[MAN_HIT], "man.bmp", 61, 61, true);

	//显示地图
	for (int i = 0; i < LINE; i++) {
		for (int j = 0; j < COLUNM; j++) {
			if (map[i][j]==MAN) {
				man.x = i;
				man.y = j;
			}
			putimage(j * 61 + START_X, i * 61 + START_Y, &images[map[i][j]]);
		}
	}
	/**************小人热键操作***************/
	//控制键 上w、下s、左a、右d 控制方向,'q' 退出
	bool quit = false;
	do {
		if (_kbhit()) //检测玩家是否有按键
		{
			char ch = _getch();
				if (ch== KEY_UP) {
					gameControl(UP);

				}
				else if(ch == KEY_LEFT ){
					gameControl(LEFT);

				}
				else if(ch == KEY_RIGHT){
					gameControl(RIGHT);

				}
				else if(ch == KEY_DOWN){
					gameControl(DOWN);

				}
				else if(ch == KEY_QUIT ){
					quit = true;

				}
				if (isGameOver()) { 
					gameOverScene(&bg_img); 
					quit = true; 
				}
		}
		Sleep(100);
	} while(quit==false);//!quit
/*****************************************/
	system("pause");
	return 0;
}

[奇牛学院]

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江凡心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值