作者GitHub-Pages个人主页
本教程GitHub-Pages链接
本教程百度云下载地址
本教程编写于2016/11/22
Dawson Lee edited this page on Beijing, 2018/7/3
设计思路
将整个画面分成13*16的矩阵,每个元素对应者一个小矩形。然后用0代表黑格,1代表白墙,2代表蓝格……,这样就有了整幅图像的信息。然后移动就可以想象成,改变矩阵的坐标信息,形成一个新的矩阵,再重绘。这就是推箱子的基本原理。
#define BLACK 0 //黑格:用于填充图像
#define WHITEWALL 1 //白墙:用于阻挡主角移动
#define BLUEWALL 2 //蓝格:用于表示可移动空间
#define BALL 3 //点:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //变色的箱子:用于表示这个点位置已经放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在点上
设计思路
步骤
1.编译环境:Visual Studio Community 2015
Tip:
- 您也可以自行百度或者google Visual Studio Community 2015的其它下载途径
- 您也可以尝试使用Visual Studio其它版本,但有可能会出现未知问题
2.要给VS2015安装EGE图形库
3.要参考EGE图形库帮助文档
Tip:如果链接失效,请自行百度或者google"EGE图形库帮助文档"
4.刚才我们说到,图像的背后对应着一个矩阵,我们可以考虑将矩阵的信息存储在一个MAP.txt文件中,在程序运行时读取。下面我来介绍,在文件中读取一个矩阵。
首先我们得有一个TXT文件:MAP.txt
(一定确保路径放置正确),它存储着这样一个13*16
的矩阵
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0
0 0 0 1 2 2 2 2 2 2 2 2 1 0 0 0
0 0 0 1 2 2 2 2 2 2 2 2 1 0 0 0
0 0 0 1 2 6 2 4 2 3 2 2 1 0 0 0
0 0 0 1 2 2 2 2 2 2 2 2 1 0 0 0
0 0 0 1 2 2 2 2 2 2 2 2 1 0 0 0
0 0 0 1 2 2 2 2 2 2 2 2 1 0 0 0
0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
文本文件中的矩阵读取操作源代码:
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp = fopen("MAP.txt", "rb");//以只读形式打开文件MAP.txt
if (!fp) {
printf("打开文件失败,文件位置你可能放错了\n");
exit(1);
}
int map[13][16];//创建一个map数组用来存储矩阵信息
int i, j;
char str[10];//用于存储从文本文件读取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++) {
fscanf(fp, "%s", str); //从文件中读取一个字符串,遇到空格结束
map[i][j] = atoi(str);//将字符串转变为整型,并赋值给map[i][j]
}
for (i = 0; i < 13; i++) {
for (j = 0; j < 16; j++) {
printf("%d", map[i][j]);//遍历输出矩阵信息
}
printf("\n");
}
return 0;
}
接下我们要把TXT文件的读取矩阵的功能,写在一个readmap()函数中,实现功能的模块化。并加多一项功能,就是查找出,MAN的位置。
//map[13][16]是形参,其中&man_i表是的是man_i的引用,引用传递的意义在于:传入参数会因函数中的操作而改变
int readmap(int map[13][16], int &man_i, int &man_j)
{
FILE *fp = fopen("MAP.txt", "rb");//以只读形式打开文件MAP.txt
if (!fp) {
printf("打开文件失败,文件位置你可能放错了\n");
exit(1);//打开失败则结束程序
}
int i, j;
char str[10];//用于存储从文本文件读取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //从文件中读取一个字符串,遇到空格结束
map[i][j] = atoi(str);//将字符串转变为整型,并赋值给map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,则返回坐标在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
5.接下来我们实现在窗口中,把矩阵信息转变成图像。原理就是,将图片贴在窗口上。
- 图片资源pic.zip(把当中的pic文件夹解压,存放在正确路径中,如果路径不正确会导致窗口中没有图像)
实现的效果如图所示:
效果图-无背景绘制操作的源代码:
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充图像
#define WHITEWALL 1 //白墙:用于阻挡主角移动
#define BLUEWALL 2 //蓝格:用于表示可移动空间
#define BALL 3 //点:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //变色的箱子:用于表示这个点位置已经放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在点上
int main()
{
int map[13][16];//创建一个map数组用来存储矩阵信息
int man_i, man_j;//用来存储人物的位置信息
int readmap(int map[13][16], int &man_x, int &man_y);//声明
void darm(int a, int ii, int jj);//声明
readmap(map, man_i, man_j);//调用readmap()函数。
initgraph(800, 650);//生成一个宽800,高650的窗口。假设矩阵元素对应的每个小矩形是50*50的,那个窗口就应该是这么大。
for (int i = 0; i<13; i++)
for (int j = 0; j < 16; j++)
{
darm(map[i][j], i, j);//遍历绘制每个小矩形
}
getch();//等待一个键盘输入,如果没有的话,窗口会看不到,因为程序运行结束就会关闭窗口。生成关闭就转瞬即逝
closegraph();//关闭窗口
return 0;
}
//map[13][16]是形参,其中&man_i表是的是man_i的引用,引用传递的意义在于:传入参数会因函数中的操作而改变
int readmap(int map[13][16], int &man_i, int &man_j)
{
FILE *fp = fopen("MAP.txt", "rb");//以只读形式打开文件MAP.txt
if (!fp) {
printf("打开文件失败,文件位置你可能放错了\n");
exit(1);//打开失败则结束程序
}
int i, j;
char str[10];//用于存储从文本文件读取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //从文件中读取一个字符串,遇到空格结束
map[i][j] = atoi(str);//将字符串转变为整型,并赋值给map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,则返回坐标在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在图形库绘制小矩形中图像的功能模块
这部分涉及C++中的知识,C语言新手不必过多纠结不懂的东西。但要知道,创建的源文件要是cpp格式的
*/
void darm(int a, int ii, int jj)
{
PIMAGE img;//声明
img = newimage();//实例化
switch (a)
{
case BLACK:break;
case WHITEWALL:
{
getimage(img, "pic/墙.jpg");//getimage()和putimage请翻阅ege图形库帮助手册。
putimage(jj * 50, ii * 50, img);//在ii行jj列绘制一个50*50像素的矩形图像
break;
}
case BLUEWALL:
{
getimage(img, "pic/路.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case BALL:
{
getimage(img, "pic/目的地.png");
putimage(jj * 50, ii * 50, img);
break;
}
case BOX:
{
getimage(img, "pic/箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
case MAN:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case MANBALL:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case REDBOX:
{
getimage(img, "pic/红箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
}
ege::delimage(img);
}
6.实现图像的绘制以后那我们就应该实现图像的移动了。
向右移动首先将所有的情况列举出来并存入数组table[i][0]
中,将改变后的第一个格子信息存在table[i][1]
中,第二个格子信息存在table[i][2]
中,第三个格子信息存在table[i][3]
中。
然后就可以开始写move()
函数,实现MAN
的移动。move()
函数源代码
/*
传入函数的参数 get表示用户输入的键盘按键,传入实时数组map的信息,传入实时MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情况的变化存在table[12][4]数组中
int table[12][4];
table[0][0] = MAN * BLUEWALL;
table[1][0] = MAN * BALL;
table[2][0] = MAN * BOX * BLUEWALL;
table[3][0] = MAN * BOX * BALL;
table[4][0] = MAN * REDBOX * BLUEWALL;
table[5][0] = MAN * REDBOX * BALL;
table[6][0] = MANBALL * BLUEWALL;
table[7][0] = MANBALL * BALL;
table[8][0] = MANBALL * BOX * BLUEWALL;
table[9][0] = MANBALL * BOX * BALL;
table[10][0] = MANBALL * REDBOX * BLUEWALL;
table[11][0] = MANBALL * REDBOX * BALL;
table[0][1] = BLUEWALL;
table[1][1] = BLUEWALL;
table[2][1] = BLUEWALL;
table[3][1] = BLUEWALL;
table[4][1] = BLUEWALL;
table[5][1] = BLUEWALL;
table[6][1] = BALL;
table[7][1] = BALL;
table[8][1] = BALL;
table[9][1] = BALL;
table[10][1] = BALL;
table[11][1] = BALL;
table[0][2] = MAN;
table[1][2] = MANBALL;
table[2][2] = MAN;
table[3][2] = MAN;
table[4][2] = MANBALL;
table[5][2] = MANBALL;
table[6][2] = MAN;
table[7][2] = MANBALL;
table[8][2] = MAN;
table[9][2] = MAN;
table[10][2] = MANBALL;
table[11][2] = MANBALL;
table[0][3] = -1;
table[1][3] = -1;
table[2][3] = BOX;
table[3][3] = REDBOX;
table[4][3] = BOX;
table[5][3] = REDBOX;
table[6][3] = -1;
table[7][3] = -1;
table[8][3] = BOX;
table[9][3] = REDBOX;
table[10][3] = BOX;
table[11][3] = REDBOX;
int i;
void darm(int a, int ii, int jj);//要用到绘制函数,所以先声明
switch (get)//switch判断用户输入的键盘信息
{
case 37: //左移,向左键的ASCII码
//for循环遍历判断MAN向左移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j - 1] * map[man_i][man_j - 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j - 1] == table[i][0])
{
//找到对应的情况后执行以下语句
map[man_i][man_j] = table[i][1];
map[man_i][man_j - 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j - 2] = table[i][3];//如果不需要改变第三个格子的图像,就不赋值。也就是如果table[i][3]==-1时。
//遍历绘制对应的三个格子信息
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j - 1], man_i, man_j - 1);
darm(map[man_i][man_j - 2], man_i, man_j - 2);
man_j--;//绘制结束后,要改变MAN的实时位置信息,并break跳出循环
break;
}
break;//再次break跳出switch语句
case 38://上移,向上键的ASCII码
//for循环遍历判断MAN向上移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i - 1][man_j] * map[man_i - 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i - 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i - 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i - 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i - 1][man_j], man_i - 1, man_j);
darm(map[man_i - 2][man_j], man_i - 2, man_j);
man_i--;
break;
}
break;
case 39://右移,向右键的ASCII码
//for循环遍历判断MAN向右移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j + 1] * map[man_i][man_j + 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j + 1] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i][man_j + 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j + 2] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j + 1], man_i, man_j + 1);
darm(map[man_i][man_j + 2], man_i, man_j + 2);
man_j++;
break;
}
break;
case 40://下移,向下键的ASCII码
//for循环遍历判断MAN向下移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i + 1][man_j] * map[man_i + 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i + 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i + 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i + 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i + 1][man_j], man_i + 1, man_j);
darm(map[man_i + 2][man_j], man_i + 2, man_j);
man_i++;
break;
}
break;
default:
break;
}
}
写好move()
函数后,我们就可以实现推箱子的功能了。整合后的源代码:
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充图像
#define WHITEWALL 1 //白墙:用于阻挡主角移动
#define BLUEWALL 2 //蓝格:用于表示可移动空间
#define BALL 3 //点:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //变色的箱子:用于表示这个点位置已经放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在点上
int main()
{
int map[13][16];//创建一个map数组用来存储矩阵信息
int man_i, man_j;//用来存储人物的位置信息
int readmap(int map[13][16], int &man_x, int &man_y);
void darm(int a, int ii, int jj);
readmap(map, man_i, man_j);//调用readmap()函数。
initgraph(800, 650);//生成一个宽800,高650的窗口。假设矩阵元素对应的每个小矩形是50*50的,那个窗口就应该是这么大。
for (int i = 0; i<13; i++)
for (int j = 0; j < 16; j++)
{
darm(map[i][j], i, j);//遍历绘制每个小矩形
}
void move(char get, int map[13][16], int &man_i, int &man_j);
char get;
for (; is_run(); delay_fps(60))//is_run()表示窗口一直显示,delay_fps(60)表示窗口以60帧的频率刷新
{
get = getch();//等待用户输入键盘按键
move(get, map, man_i, man_j);
}
closegraph();//关闭窗口
return 0;
}
//map[13][16]是形参,其中&man_i表是的是man_i的引用,引用传递的意义在于:传入参数会因函数中的操作而改变
int readmap(int map[13][16], int &man_i, int &man_j)
{
FILE *fp = fopen("MAP.txt", "rb");//以只读形式打开文件MAP.txt
if (!fp) {
printf("打开文件失败,文件位置你可能放错了\n");
exit(1);//打开失败则结束程序
}
int i, j;
char str[10];//用于存储从文本文件读取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //从文件中读取一个字符串,遇到空格结束
map[i][j] = atoi(str);//将字符串转变为整型,并赋值给map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,则返回坐标在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在图形库绘制小矩形中图像的功能模块
这部分涉及C++中的知识,C语言新手不必过多纠结不懂的东西。但要知道,创建的源文件要是cpp格式的
*/
void darm(int a, int ii, int jj)
{
PIMAGE img;//声明
img = newimage();//实例化
switch (a)
{
case BLACK:break;
case WHITEWALL:
{
getimage(img, "pic/墙.jpg");//getimage()和putimage请翻阅ege图形库帮助手册。
putimage(jj * 50, ii * 50, img);//在ii行jj列绘制一个50*50像素的矩形图像
break;
}
case BLUEWALL:
{
getimage(img, "pic/路.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case BALL:
{
getimage(img, "pic/目的地.png");
putimage(jj * 50, ii * 50, img);
break;
}
case BOX:
{
getimage(img, "pic/箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
case MAN:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case MANBALL:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case REDBOX:
{
getimage(img, "pic/红箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
}
ege::delimage(img);
}
/*
传入函数的参数 get表示用户输入的键盘按键,传入实时数组map的信息,传入实时MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情况的变化存在table[12][4]数组中
int table[12][4];
table[0][0] = MAN * BLUEWALL;
table[1][0] = MAN * BALL;
table[2][0] = MAN * BOX * BLUEWALL;
table[3][0] = MAN * BOX * BALL;
table[4][0] = MAN * REDBOX * BLUEWALL;
table[5][0] = MAN * REDBOX * BALL;
table[6][0] = MANBALL * BLUEWALL;
table[7][0] = MANBALL * BALL;
table[8][0] = MANBALL * BOX * BLUEWALL;
table[9][0] = MANBALL * BOX * BALL;
table[10][0] = MANBALL * REDBOX * BLUEWALL;
table[11][0] = MANBALL * REDBOX * BALL;
table[0][1] = BLUEWALL;
table[1][1] = BLUEWALL;
table[2][1] = BLUEWALL;
table[3][1] = BLUEWALL;
table[4][1] = BLUEWALL;
table[5][1] = BLUEWALL;
table[6][1] = BALL;
table[7][1] = BALL;
table[8][1] = BALL;
table[9][1] = BALL;
table[10][1] = BALL;
table[11][1] = BALL;
table[0][2] = MAN;
table[1][2] = MANBALL;
table[2][2] = MAN;
table[3][2] = MAN;
table[4][2] = MANBALL;
table[5][2] = MANBALL;
table[6][2] = MAN;
table[7][2] = MANBALL;
table[8][2] = MAN;
table[9][2] = MAN;
table[10][2] = MANBALL;
table[11][2] = MANBALL;
table[0][3] = -1;
table[1][3] = -1;
table[2][3] = BOX;
table[3][3] = REDBOX;
table[4][3] = BOX;
table[5][3] = REDBOX;
table[6][3] = -1;
table[7][3] = -1;
table[8][3] = BOX;
table[9][3] = REDBOX;
table[10][3] = BOX;
table[11][3] = REDBOX;
int i;
void darm(int a, int ii, int jj);//要用到绘制函数,所以先声明
switch (get)//switch判断用户输入的键盘信息
{
case 37: //左移,向左键的ASCII码
//for循环遍历判断MAN向左移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j - 1] * map[man_i][man_j - 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j - 1] == table[i][0])
{
//找到对应的情况后执行以下语句
map[man_i][man_j] = table[i][1];
map[man_i][man_j - 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j - 2] = table[i][3];//如果不需要改变第三个格子的图像,就不赋值。也就是如果table[i][3]==-1时。
//遍历绘制对应的三个格子信息
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j - 1], man_i, man_j - 1);
darm(map[man_i][man_j - 2], man_i, man_j - 2);
man_j--;//绘制结束后,要改变MAN的实时位置信息,并break跳出循环
break;
}
break;//再次break跳出switch语句
case 38://上移,向上键的ASCII码
//for循环遍历判断MAN向上移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i - 1][man_j] * map[man_i - 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i - 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i - 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i - 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i - 1][man_j], man_i - 1, man_j);
darm(map[man_i - 2][man_j], man_i - 2, man_j);
man_i--;
break;
}
break;
case 39://右移,向右键的ASCII码
//for循环遍历判断MAN向右移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j + 1] * map[man_i][man_j + 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j + 1] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i][man_j + 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j + 2] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j + 1], man_i, man_j + 1);
darm(map[man_i][man_j + 2], man_i, man_j + 2);
man_j++;
break;
}
break;
case 40://下移,向下键的ASCII码
//for循环遍历判断MAN向下移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i + 1][man_j] * map[man_i + 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i + 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i + 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i + 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i + 1][man_j], man_i + 1, man_j);
darm(map[man_i + 2][man_j], man_i + 2, man_j);
man_i++;
break;
}
break;
default:
break;
}
}
7.最后,我们给窗口载入一张完美的背景图片,至此就可以实现完整推箱子小游戏了。
实际效果图:
效果图-背景
最后整合的代码就是:
/*
作者:DawsonLee
Email:dawsonlee1790@foxmail.com
*/
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充图像
#define WHITEWALL 1 //白墙:用于阻挡主角移动
#define BLUEWALL 2 //蓝格:用于表示可移动空间
#define BALL 3 //点:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //变色的箱子:用于表示这个点位置已经放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在点上
int main()
{
int map[13][16];//创建一个map数组用来存储矩阵信息
int man_i, man_j;//用来存储人物的位置信息
int readmap(int map[13][16], int &man_x, int &man_y);
void darm(int a, int ii, int jj);
readmap(map, man_i, man_j);//调用readmap()函数。
initgraph(800, 650);//生成一个宽800,高650的窗口。假设矩阵元素对应的每个小矩形是50*50的,那个窗口就应该是这么大。
//载入一张漂亮的背景图片
PIMAGE imgui;
imgui = newimage();
getimage(imgui, "pic/背景.jpg");
putimage(0, 0, imgui);
for (int i = 0; i<13; i++)
for (int j = 0; j < 16; j++)
{
darm(map[i][j], i, j);//遍历绘制每个小矩形
}
void move(char get, int map[13][16], int &man_i, int &man_j);
char get;
for (; is_run(); delay_fps(60))//is_run()表示窗口一直显示,delay_fps(60)表示窗口以60帧的频率刷新
{
get = getch();//等待用户输入键盘按键
move(get, map, man_i, man_j);
}
closegraph();//关闭窗口
return 0;
}
int readmap(int map[13][16], int &man_i, int &man_j)//map[13][16]是形参,其中&man_i表是的是man_i的引用,引用传递的意义在于:传入参数会因函数中的操作而改变
{
FILE *fp = fopen("MAP.txt", "rb");//以只读形式打开文件MAP.txt
if (!fp) {
printf("打开文件失败,文件位置你可能放错了\n");
exit(1);//打开失败则结束程序
}
int i, j;
char str[10];//用于存储从文本文件读取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //从文件中读取一个字符串,遇到空格结束
map[i][j] = atoi(str);//将字符串转变为整型,并赋值给map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,则返回坐标在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在图形库绘制小矩形中图像的功能模块
这部分涉及C++中的知识,C语言新手不必过多纠结不懂的东西。但要知道,创建的源文件要是cpp格式的
*/
void darm(int a, int ii, int jj)
{
PIMAGE img;//声明
img = newimage();//实例化
switch (a)
{
case BLACK:break;
case WHITEWALL:
{
getimage(img, "pic/墙.jpg");//getimage()和putimage请翻阅ege图形库帮助手册。
putimage(jj * 50, ii * 50, img);//在ii行jj列绘制一个50*50像素的矩形图像
break;
}
case BLUEWALL:
{
getimage(img, "pic/路.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case BALL:
{
getimage(img, "pic/目的地.png");
putimage(jj * 50, ii * 50, img);
break;
}
case BOX:
{
getimage(img, "pic/箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
case MAN:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case MANBALL:
{
getimage(img, "pic/人.jpg");
putimage(jj * 50, ii * 50, img);
break;
}
case REDBOX:
{
getimage(img, "pic/红箱子.png");
putimage(jj * 50, ii * 50, img);
break;
}
}
ege::delimage(img);
}
/*
传入函数的参数 get表示用户输入的键盘按键,传入实时数组map的信息,传入实时MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情况的变化存在table[12][4]数组中
int table[12][4];
table[0][0] = MAN * BLUEWALL;
table[1][0] = MAN * BALL;
table[2][0] = MAN * BOX * BLUEWALL;
table[3][0] = MAN * BOX * BALL;
table[4][0] = MAN * REDBOX * BLUEWALL;
table[5][0] = MAN * REDBOX * BALL;
table[6][0] = MANBALL * BLUEWALL;
table[7][0] = MANBALL * BALL;
table[8][0] = MANBALL * BOX * BLUEWALL;
table[9][0] = MANBALL * BOX * BALL;
table[10][0] = MANBALL * REDBOX * BLUEWALL;
table[11][0] = MANBALL * REDBOX * BALL;
table[0][1] = BLUEWALL;
table[1][1] = BLUEWALL;
table[2][1] = BLUEWALL;
table[3][1] = BLUEWALL;
table[4][1] = BLUEWALL;
table[5][1] = BLUEWALL;
table[6][1] = BALL;
table[7][1] = BALL;
table[8][1] = BALL;
table[9][1] = BALL;
table[10][1] = BALL;
table[11][1] = BALL;
table[0][2] = MAN;
table[1][2] = MANBALL;
table[2][2] = MAN;
table[3][2] = MAN;
table[4][2] = MANBALL;
table[5][2] = MANBALL;
table[6][2] = MAN;
table[7][2] = MANBALL;
table[8][2] = MAN;
table[9][2] = MAN;
table[10][2] = MANBALL;
table[11][2] = MANBALL;
table[0][3] = -1;
table[1][3] = -1;
table[2][3] = BOX;
table[3][3] = REDBOX;
table[4][3] = BOX;
table[5][3] = REDBOX;
table[6][3] = -1;
table[7][3] = -1;
table[8][3] = BOX;
table[9][3] = REDBOX;
table[10][3] = BOX;
table[11][3] = REDBOX;
int i;
void darm(int a, int ii, int jj);//要用到绘制函数,所以先声明
switch (get)//switch判断用户输入的键盘信息
{
case 37: //左移,向左键的ASCII码
//for循环遍历判断MAN向左移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j - 1] * map[man_i][man_j - 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j - 1] == table[i][0])
{
//找到对应的情况后执行以下语句
map[man_i][man_j] = table[i][1];
map[man_i][man_j - 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j - 2] = table[i][3];//如果不需要改变第三个格子的图像,就不赋值。也就是如果table[i][3]==-1时。
//遍历绘制对应的三个格子信息
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j - 1], man_i, man_j - 1);
darm(map[man_i][man_j - 2], man_i, man_j - 2);
man_j--;//绘制结束后,要改变MAN的实时位置信息,并break跳出循环
break;
}
break;//再次break跳出switch语句
case 38://上移,向上键的ASCII码
//for循环遍历判断MAN向上移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i - 1][man_j] * map[man_i - 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i - 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i - 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i - 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i - 1][man_j], man_i - 1, man_j);
darm(map[man_i - 2][man_j], man_i - 2, man_j);
man_i--;
break;
}
break;
case 39://右移,向右键的ASCII码
//for循环遍历判断MAN向右移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i][man_j + 1] * map[man_i][man_j + 2] == table[i][0] ||
map[man_i][man_j] * map[man_i][man_j + 1] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i][man_j + 1] = table[i][2];
if (table[i][3] != -1)map[man_i][man_j + 2] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i][man_j + 1], man_i, man_j + 1);
darm(map[man_i][man_j + 2], man_i, man_j + 2);
man_j++;
break;
}
break;
case 40://下移,向下键的ASCII码
//for循环遍历判断MAN向下移动对应的是哪种情况
for (i = 0; i < 12; i++)
if (map[man_i][man_j] * map[man_i + 1][man_j] * map[man_i + 2][man_j] == table[i][0] ||
map[man_i][man_j] * map[man_i + 1][man_j] == table[i][0])
{
map[man_i][man_j] = table[i][1];
map[man_i + 1][man_j] = table[i][2];
if (table[i][3] != -1)map[man_i + 2][man_j] = table[i][3];
darm(map[man_i][man_j], man_i, man_j);
darm(map[man_i + 1][man_j], man_i + 1, man_j);
darm(map[man_i + 2][man_j], man_i + 2, man_j);
man_i++;
break;
}
break;
default:
break;
}
}
网友评论