推箱子游戏简化版
最近看笔记的时候, 突然看到了以前做过的推箱子小游戏.下面是整理的内容
-
(1)游戏图片资源:
链接:https://pan.baidu.com/s/1XQWHwwlh_oiHKScbF-IkCg 提取码:rlel (个人百度网盘链接)
控件easyX的下载资源:
www.easyx.cn 注意:把图形资源要放在存储代码的.cpp文件里
-
(2) 项目需求:
需要达到的效果如下图所示:
规则如下:
1.箱子只能向前推,不能后退,也就是说一但推到死角就失败了
2.推箱子的小人不能穿过木板,箱子目的地和箱子
3.当所有的箱子都被成功推到目的地时,游戏就结束,需要被提醒过关成功`在这里插入代码片
-
(3)个人分析:
在做一个小软件的时候,感觉最禁忌的就是说我要一次性写多少代码.应该最先把要设计的软件各个功能都想好.只有当我们把功能想好了,才可以来设计函数来一个个实现.一次性能把所有功能都写出来对于新手来说几乎是不可能的.尤其是c++这门语言,我感觉刚开始在准备写代码去实现软件时,最重要的就是要明白编写这个软件的目的就是我要做什么东西,需要把这个要做的逻辑结构理清楚.然后在用一个个函数去实现.把难的模块分成一个个简单的模块,这样才能化繁为简.
-
(4)游戏的整体模块划分:
1:地图初始化
用easyX图形库搭建一个背景,用来初始化地图,并初始化坐标系,指定长度和宽度
首先要明白easyX的x,y坐标跟我们平时理解的有点差异的:如下
代码实现:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
int main(void) {
initgraph(800,650); //初始化地图
system("pause");
return 0;
}
程序运行结果:
搭舞台:
后续代码:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(800,650); //初始化地图
loadimage(&bg_img,"blackground.bmp",800,650,true);
putimage(0,0,&bg_img); //放准备好的背景图片放入控制台界面
system("pause");
return 0;
}
程序运行结果:
- 地图如何表示,地图里面的元素如何定义
1.地图只是平面的,所以用二维数组就能够去描述了它了
2.道具的表示:
墙: 0 地板: 1 箱子目的地: 2 小人: 3 箱子: 4 箱子命中目标: 5
代码实现:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(800,650); //初始化地图
loadimage(&bg_img,"blackground.bmp",800,650,true);
putimage(0,0,&bg_img); //放准备好的背景图片放入控制台界面
IMAGE images[6]; //定义全局数组 里面只有0-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, 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, 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 }, };
//加载道具图标
loadimage(&images[0], _T("wall.bmp"), 50, 50, true);
loadimage(&images[1], _T("floor.bmp"), 50, 50, true);
loadimage(&images[2], _T("des.bmp"), 50, 50, true);
loadimage(&images[3], _T("man.bmp"), 50, 50, true);
loadimage(&images[4], _T("box.bmp"), 50, 50, true);
loadimage(&images[5], _T("box.bmp"), 50, 50, true);
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 12; j++) {
putimage(100 + j * 50, 100 + i * 50, &images[map[i][j]]);
}
}
system("pause");
return 0;
}
程序运行结果:
- 注:后面应该把所有的数字常量全部换成宏定义,方面以后修改维护,也能提高代码可读性
修改后的代码:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
using namespace std;
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH , SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img,"blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT,true);
putimage(0,0,&bg_img); //放准备好的背景图片放入控制台界面
IMAGE images[6]; //定义全局数组 里面只有0-5这六种元素
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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 }, };
//加载道具图标
loadimage(&images[0], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[1], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[2], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[3], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[4], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[5], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN ; j++) {
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
system("pause");
return 0;
}
再次优化代码:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
using namespace std;
enum _PROPS{
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
struct _POS{
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man;
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH , SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img,"blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT,true);
putimage(0,0,&bg_img); //放准备好的背景图片放入控制台界面
IMAGE images[ALL]; //定义全局数组 里面只有0-5这六种元素
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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 }, };
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN ; j++) {
if(map[i][j]==MAN){
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
system("pause");
return 0;
}
-
2:热键控制
1)定义热键:
左 => a 下=> s 上=> w 右 => d 退出 => q
代码实现:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#include<conio.h>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
using namespace std;
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man; 小人在二维数组中的位置
IMAGE images[ALL]; //定义全局数组 里面只有0-5这六种元素
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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 }, };
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img, "blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //放准备好的背景图片放入控制台界面
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == MAN) {
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
//游戏设置环节
bool quit = false;
do {
if (_kbhit()) {//玩家按键
char ch = _getch();
if (ch == KEY_UP) { //向上键
}
else if (ch == KEY_DOWN) {
}
else if (ch == KEY_LEFT) {
}
else if (ch == KEY_RIGHT) {
}
else if (ch == KEY_QUIT) {
quit = true;
}
}
Sleep(100); //休眠处理
}while (quit == false);
system("pause");
return 0;
}
- 3 推箱子控制:
代码实现:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#include<conio.h>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#define KEY_UP 'w'
#define KEY_LEFT 'a'
#define KEY_RIGHT 'd'
#define KEY_DOWN 's'
#define KEY_QUIT 'q'
using namespace std;
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
//游戏控制方向
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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]; //定义全局数组 里面只有0-5这六种元素
//改变游戏地图视图中一格对应道具并重新显示
//line:道具在地图数组的行下标 column:道具在地图数组的列下标 prop:道具的类型(比如是人或许其他东西)
void changeMap(int line, int column, enum _PROPS prop) {
map[line][column] = prop;
putimage(START_X + column * RATIO, START_Y + line * RATIO, &images[prop]);
}
/*
*实现游戏四个方向(上、下、左、右)的控制
* 输入: * direct - 人前进方向
* 输出: 无
*/
void gameControl(enum _DIRECTION direct) {
int x = man.x;
int y = man.y;
if (direct == UP) { //先处理前进方向时地板的情况 x-1
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) > 0 && 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) > 0 && map[x][y + 1] == FLOOR) {
changeMap(x , y+1, MAN); //小人向右一格
man.y = y + 1;
changeMap(x, y, FLOOR);
}
}
}
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img, "blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //放准备好的背景图片放入控制台界面
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == MAN) {
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
//游戏设置环节
bool quit = false;
do {
if (_kbhit()) {//玩家按键
char ch = _getch();
if (ch == KEY_UP) { //向上键
gameControl(UP);
}
else if (ch == KEY_DOWN) {
gameControl(DOWN);
}
else if (ch == KEY_LEFT) {
gameControl(LEFT);
}
else if (ch == KEY_RIGHT) {
gameControl(RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
}
Sleep(100); //休眠处理
}while (quit == false);
system("pause");
return 0;
}
- 做到这里就可以控制小人在地图里面行走了!(其实真的运行下来,发现代码里面的知识点真的很少的,很容易掌握的)
代码优化:(void gameControl(enum _DIRECTION direct){})
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#include<conio.h>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#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 < COLUMN
using namespace std;
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
//游戏控制方向
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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]; //定义全局数组 里面只有0-5这六种元素
//改变游戏地图视图中一格对应道具并重新显示
//line:道具在地图数组的行下标 column:道具在地图数组的列下标 prop:道具的类型(比如是人或许其他东西)
void changeMap(int line, int column, enum _PROPS prop) {
map[line][column] = prop;
putimage(START_X + column * RATIO, START_Y + line * RATIO, &images[prop]);
}
/*
*实现游戏四个方向(上、下、左、右)的控制
* 输入: * direct - 人前进方向
* 输出: 无
*/
void gameControl(enum _DIRECTION direct) {
//int x = man.x;
//int y = man.y;
struct _POS next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
break;
case DOWN:
next_pos.x++;
break;
case LEFT:
next_pos.y--;
break;
case RIGHT:
next_pos.y++;
break;
}
/*
if (direct == UP) { //先处理前进方向时地板的情况 x-1
if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人前进一格
changeMap(man.x,man.y,FLOOR);
man = next_pos;
}
}else if (direct == DOWN) {
if ((x + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人后进一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == LEFT) {
if ((y - 1) >= 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向左一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == RIGHT) {
if ((y + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向右一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}*/ //这些代码都是重复地,可以替换成下面的代码
//if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
//if (next_pos.x >= 0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y<COLUMN && map[next_pos.x][next_pos.y]) { //判断合法性检查
//宏展开 next_pos.x>=0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y <COLUMN
if (isValid(next_pos) && map[next_pos.x][next_pos.y]) { //用宏代替
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img, "blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //放准备好的背景图片放入控制台界面
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == MAN) {
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
//游戏设置环节
bool quit = false;
do {
if (_kbhit()) {//玩家按键
char ch = _getch();
if (ch == KEY_UP) { //向上键
gameControl(UP);
}
else if (ch == KEY_DOWN) {
gameControl(DOWN);
}
else if (ch == KEY_LEFT) {
gameControl(LEFT);
}
else if (ch == KEY_RIGHT) {
gameControl(RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
}
Sleep(100); //休眠处理
}while (quit == false);
system("pause");
return 0;
}
再次补充缺少条件跟优化代码:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#include<conio.h>
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#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 < COLUMN
using namespace std;
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
//游戏控制方向
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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]; //定义全局数组 里面只有0-5这六种元素
//改变游戏地图视图中一格对应道具并重新显示
//line:道具在地图数组的行下标 column:道具在地图数组的列下标 prop:道具的类型(比如是人或许其他东西)
void changeMap(int line, int column, enum _PROPS prop) {
map[line][column] = prop;
putimage(START_X + column * RATIO, START_Y + line * RATIO, &images[prop]);
}
/*
*实现游戏四个方向(上、下、左、右)的控制
* 输入: * direct - 人前进方向
* 输出: 无
*/
void gameControl(enum _DIRECTION direct) {
//int x = man.x;
//int y = man.y;
struct _POS next_pos = man;
struct _POS next_next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
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 (direct == UP) { //先处理前进方向时地板的情况 x-1
if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人前进一格
changeMap(man.x,man.y,FLOOR);
man = next_pos;
}
}else if (direct == DOWN) {
if ((x + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人后进一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == LEFT) {
if ((y - 1) >= 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向左一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == RIGHT) {
if ((y + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向右一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}*/ //这些代码都是重复地,可以替换成下面的代码
//if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
//if (next_pos.x >= 0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y<COLUMN && map[next_pos.x][next_pos.y]) { //判断合法性检查
//宏展开 next_pos.x>=0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y <COLUMN
if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR ) { //用宏代替 //如果人要走的前方是地板
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
else if (isValid(next_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.x, next_next_pos.y, BOX);
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
else if (map[next_next_pos.x][next_next_pos.y] == BOX_DES) {
changeMap(next_next_pos.x, next_next_pos.y, HIT);
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img, "blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //放准备好的背景图片放入控制台界面
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == MAN) {
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
//游戏设置环节
bool quit = false;
do {
if (_kbhit()) {//玩家按键
char ch = _getch();
if (ch == KEY_UP) { //向上键
gameControl(UP);
}
else if (ch == KEY_DOWN) {
gameControl(DOWN);
}
else if (ch == KEY_LEFT) {
gameControl(LEFT);
}
else if (ch == KEY_RIGHT) {
gameControl(RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
}
Sleep(100); //休眠处理
}while (quit == false);
//游戏结束,释放资源
closegraph();
system("pause");
return 0;
}
-
其实到这里就几乎做完了,唯一差的就是一个结束条件了
-
4 游戏结束
#include //使用easyX需要添加的头文件
#include
#include
#include
#include
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#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 < COLUMN
using namespace std;
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
//游戏控制方向
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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 }, };
/*
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* true - 游戏结束
false - 游戏继续
*/
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;
}
/*
*游戏结束场景,在玩家通关后显示
* 输入: * 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);//居中对齐,具体看easyX的文档
}
IMAGE images[ALL]; //定义全局数组 里面只有0-5这六种元素
//改变游戏地图视图中一格对应道具并重新显示
//line:道具在地图数组的行下标 column:道具在地图数组的列下标 prop:道具的类型(比如是人或许其他东西)
void changeMap(int line, int column, enum _PROPS prop) {
map[line][column] = prop;
putimage(START_X + column * RATIO, START_Y + line * RATIO, &images[prop]);
}
/*
*实现游戏四个方向(上、下、左、右)的控制
* 输入: * direct - 人前进方向
* 输出: 无
*/
void gameControl(enum _DIRECTION direct) {
//int x = man.x;
//int y = man.y;
struct _POS next_pos = man;
struct _POS next_next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
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 (direct == UP) { //先处理前进方向时地板的情况 x-1
if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人前进一格
changeMap(man.x,man.y,FLOOR);
man = next_pos;
}
}else if (direct == DOWN) {
if ((x + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人后进一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == LEFT) {
if ((y - 1) >= 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向左一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == RIGHT) {
if ((y + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向右一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}*/ //这些代码都是重复地,可以替换成下面的代码
//if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
//if (next_pos.x >= 0 && next_pos.x=0 && next_pos.y=0 && next_pos.x=0 && next_pos.y
上面为补充结束条件代码,也为整个游戏的完整代码
-
游戏结束后,可以把游戏里的定义,头文件,宏定义等文件,封装到一个头文件里面,
-
头文件里代码如下:
#pragma once
#define RATIO 50
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 650
#define LINE 9
#define COLUMN 12
#define START_X 100
#define START_Y 100
//控制键 上、下、左、右 控制方向,'q' 退出
#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 < COLUMN
enum _PROPS {
WALL, //表示墙:0
FLOOR, //表示地板:1
BOX_DES, //表示箱子目的地:2
MAN, //表示小人:3
BOX, //表示箱子:4
HIT, //表示箱子命中目标:5
ALL //表示定义全局数组里的个数:6
};
//游戏控制方向
enum _DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
struct _POS {
int x; //小人在二维数组里位置的行
int y; //小人在二维数组里位置的列
};
源文件里代码如下:
#include <graphics.h> //使用easyX需要添加的头文件
#include <iostream>
#include <stdlib.h>
#include <string>
#include<conio.h>
#include"box_man1.h"
using namespace std;
struct _POS man; //小人在二维数组中的位置
/*游戏地图*/
int map[LINE][COLUMN] = {
{ 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, 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 }, };
/*
*判断游戏是否结束,如果不存在任何一个箱子目的地,就代表游戏结束
*输入: 无
*返回值:
* true - 游戏结束
false - 游戏继续
*/
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;
}
/*
*游戏结束场景,在玩家通关后显示
* 输入: * 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);//居中对齐,具体看easyX的文档
}
IMAGE images[ALL]; //定义全局数组 里面只有0-5这六种元素
//改变游戏地图视图中一格对应道具并重新显示
//line:道具在地图数组的行下标 column:道具在地图数组的列下标 prop:道具的类型(比如是人或许其他东西)
void changeMap(int line, int column, enum _PROPS prop) {
map[line][column] = prop;
putimage(START_X + column * RATIO, START_Y + line * RATIO, &images[prop]);
}
/*
*实现游戏四个方向(上、下、左、右)的控制
* 输入: * direct - 人前进方向
* 输出: 无
*/
void gameControl(enum _DIRECTION direct) {
//int x = man.x;
//int y = man.y;
struct _POS next_pos = man;
struct _POS next_next_pos = man;
switch (direct) {
case UP:
next_pos.x--;
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 (direct == UP) { //先处理前进方向时地板的情况 x-1
if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人前进一格
changeMap(man.x,man.y,FLOOR);
man = next_pos;
}
}else if (direct == DOWN) {
if ((x + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人后进一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == LEFT) {
if ((y - 1) >= 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向左一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}else if (direct == RIGHT) {
if ((y + 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
changeMap(next_pos.x, y, MAN); //小人向右一格
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}*/ //这些代码都是重复地,可以替换成下面的代码
//if ((x - 1) > 0 && map[next_pos.x][next_pos.y] == FLOOR) {
//if (next_pos.x >= 0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y<COLUMN && map[next_pos.x][next_pos.y]) { //判断合法性检查
//宏展开 next_pos.x>=0 && next_pos.x<LINE && next_pos.y>=0 && next_pos.y <COLUMN
if (isValid(next_pos) && map[next_pos.x][next_pos.y] == FLOOR ) { //用宏代替 //如果人要走的前方是地板
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
else if (isValid(next_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.x, next_next_pos.y, BOX);
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
else if (map[next_next_pos.x][next_next_pos.y] == BOX_DES) {
changeMap(next_next_pos.x, next_next_pos.y, HIT);
changeMap(next_pos.x, next_pos.y, MAN);
changeMap(man.x, man.y, FLOOR);
man = next_pos;
}
}
}
int main(void) {
IMAGE bg_img;
//地图搭台
initgraph(SCREEN_WIDTH, SCREEN_HEIGHT); //初始化地图
loadimage(&bg_img, "blackground.bmp", SCREEN_WIDTH, SCREEN_HEIGHT, true);
putimage(0, 0, &bg_img); //放准备好的背景图片放入控制台界面
//加载道具图标
loadimage(&images[WALL], _T("wall.bmp"), RATIO, RATIO, true);
loadimage(&images[FLOOR], _T("floor.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX_DES], _T("des.bmp"), RATIO, RATIO, true);
loadimage(&images[MAN], _T("man.bmp"), RATIO, RATIO, true);
loadimage(&images[BOX], _T("box.bmp"), RATIO, RATIO, true);
loadimage(&images[HIT], _T("box.bmp"), RATIO, RATIO, true);
for (int i = 0; i < LINE; i++) {
for (int j = 0; j < COLUMN; j++) {
if (map[i][j] == MAN) {
man.x = i;
man.y = j;
}
putimage(START_X + j * RATIO, START_Y + i * RATIO, &images[map[i][j]]);
}
}
//游戏设置环节
bool quit = false;
do {
if (_kbhit()) {//玩家按键
char ch = _getch();
if (ch == KEY_UP) { //向上键
gameControl(UP);
}
else if (ch == KEY_DOWN) {
gameControl(DOWN);
}
else if (ch == KEY_LEFT) {
gameControl(LEFT);
}
else if (ch == KEY_RIGHT) {
gameControl(RIGHT);
}
else if (ch == KEY_QUIT) {
quit = true;
}
if (isGameOver()) {
gameOverScene(&bg_img);
quit = true;
}
}
Sleep(100); //休眠处理
}while (quit == false);
system("pause");
//游戏结束,释放资源
closegraph();
return 0;
}