作者GitHub-Pages個人主頁
本教程GitHub-Pages鏈接
本教程百度云下載地址
本教程編寫于2016/11/22
Dawson Lee edited this page on Beijing, 2018/7/3
設(shè)計思路
將整個畫面分成13*16的矩陣,每個元素對應(yīng)者一個小矩形。然后用0代表黑格,1代表白墻,2代表藍(lán)格……,這樣就有了整幅圖像的信息。然后移動就可以想象成,改變矩陣的坐標(biāo)信息,形成一個新的矩陣,再重繪。這就是推箱子的基本原理。
#define BLACK 0 //黑格:用于填充圖像
#define WHITEWALL 1 //白墻:用于阻擋主角移動
#define BLUEWALL 2 //藍(lán)格:用于表示可移動空間
#define BALL 3 //點:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //變色的箱子:用于表示這個點位置已經(jīng)放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在點上

設(shè)計思路
步驟
1.編譯環(huán)境:Visual Studio Community 2015
Tip:
- 您也可以自行百度或者google Visual Studio Community 2015的其它下載途徑
- 您也可以嘗試使用Visual Studio其它版本,但有可能會出現(xiàn)未知問題
2.要給VS2015安裝EGE圖形庫
3.要參考EGE圖形庫幫助文檔
Tip:如果鏈接失效,請自行百度或者google"EGE圖形庫幫助文檔"
4.剛才我們說到,圖像的背后對應(yīng)著一個矩陣,我們可以考慮將矩陣的信息存儲在一個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];//創(chuàng)建一個map數(shù)組用來存儲矩陣信息
int i, j;
char str[10];//用于存儲從文本文件讀取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++) {
fscanf(fp, "%s", str); //從文件中讀取一個字符串,遇到空格結(jié)束
map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎?,并賦值給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()函數(shù)中,實現(xiàn)功能的模塊化。并加多一項功能,就是查找出,MAN的位置。
//map[13][16]是形參,其中&man_i表是的是man_i的引用,引用傳遞的意義在于:傳入?yún)?shù)會因函數(shù)中的操作而改變
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);//打開失敗則結(jié)束程序
}
int i, j;
char str[10];//用于存儲從文本文件讀取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //從文件中讀取一個字符串,遇到空格結(jié)束
map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎?,并賦值給map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,則返回坐標(biāo)在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
5.接下來我們實現(xiàn)在窗口中,把矩陣信息轉(zhuǎn)變成圖像。原理就是,將圖片貼在窗口上。
- 圖片資源pic.zip(把當(dāng)中的pic文件夾解壓,存放在正確路徑中,如果路徑不正確會導(dǎo)致窗口中沒有圖像)
實現(xiàn)的效果如圖所示:

效果圖-無背景
繪制操作的源代碼:
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充圖像
#define WHITEWALL 1 //白墻:用于阻擋主角移動
#define BLUEWALL 2 //藍(lán)格:用于表示可移動空間
#define BALL 3 //點:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //變色的箱子:用于表示這個點位置已經(jīng)放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在點上
int main()
{
int map[13][16];//創(chuàng)建一個map數(shù)組用來存儲矩陣信息
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);//調(diào)用readmap()函數(shù)。
initgraph(800, 650);//生成一個寬800,高650的窗口。假設(shè)矩陣元素對應(yīng)的每個小矩形是50*50的,那個窗口就應(yīng)該是這么大。
for (int i = 0; i<13; i++)
for (int j = 0; j < 16; j++)
{
darm(map[i][j], i, j);//遍歷繪制每個小矩形
}
getch();//等待一個鍵盤輸入,如果沒有的話,窗口會看不到,因為程序運行結(jié)束就會關(guān)閉窗口。生成關(guān)閉就轉(zhuǎn)瞬即逝
closegraph();//關(guān)閉窗口
return 0;
}
//map[13][16]是形參,其中&man_i表是的是man_i的引用,引用傳遞的意義在于:傳入?yún)?shù)會因函數(shù)中的操作而改變
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);//打開失敗則結(jié)束程序
}
int i, j;
char str[10];//用于存儲從文本文件讀取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //從文件中讀取一個字符串,遇到空格結(jié)束
map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎?,并賦值給map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,則返回坐標(biāo)在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在圖形庫繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識,C語言新手不必過多糾結(jié)不懂的東西。但要知道,創(chuàng)建的源文件要是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.實現(xiàn)圖像的繪制以后那我們就應(yīng)該實現(xiàn)圖像的移動了。

向右移動
首先將所有的情況列舉出來并存入數(shù)組table[i][0]中,將改變后的第一個格子信息存在table[i][1]中,第二個格子信息存在table[i][2]中,第三個格子信息存在table[i][3]中。

數(shù)組table
然后就可以開始寫move()函數(shù),實現(xiàn)MAN的移動。move()函數(shù)源代碼
/*
傳入函數(shù)的參數(shù) get表示用戶輸入的鍵盤按鍵,傳入實時數(shù)組map的信息,傳入實時MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情況的變化存在table[12][4]數(shù)組中
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);//要用到繪制函數(shù),所以先聲明
switch (get)//switch判斷用戶輸入的鍵盤信息
{
case 37: //左移,向左鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向左移動對應(yīng)的是哪種情況
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])
{
//找到對應(yīng)的情況后執(zhí)行以下語句
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時。
//遍歷繪制對應(yīng)的三個格子信息
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--;//繪制結(jié)束后,要改變MAN的實時位置信息,并break跳出循環(huán)
break;
}
break;//再次break跳出switch語句
case 38://上移,向上鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向上移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向右移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向下移動對應(yīng)的是哪種情況
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()函數(shù)后,我們就可以實現(xiàn)推箱子的功能了。整合后的源代碼:
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充圖像
#define WHITEWALL 1 //白墻:用于阻擋主角移動
#define BLUEWALL 2 //藍(lán)格:用于表示可移動空間
#define BALL 3 //點:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //變色的箱子:用于表示這個點位置已經(jīng)放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在點上
int main()
{
int map[13][16];//創(chuàng)建一個map數(shù)組用來存儲矩陣信息
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);//調(diào)用readmap()函數(shù)。
initgraph(800, 650);//生成一個寬800,高650的窗口。假設(shè)矩陣元素對應(yīng)的每個小矩形是50*50的,那個窗口就應(yīng)該是這么大。
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();//關(guān)閉窗口
return 0;
}
//map[13][16]是形參,其中&man_i表是的是man_i的引用,引用傳遞的意義在于:傳入?yún)?shù)會因函數(shù)中的操作而改變
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);//打開失敗則結(jié)束程序
}
int i, j;
char str[10];//用于存儲從文本文件讀取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //從文件中讀取一個字符串,遇到空格結(jié)束
map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎?,并賦值給map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,則返回坐標(biāo)在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在圖形庫繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識,C語言新手不必過多糾結(jié)不懂的東西。但要知道,創(chuàng)建的源文件要是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);
}
/*
傳入函數(shù)的參數(shù) get表示用戶輸入的鍵盤按鍵,傳入實時數(shù)組map的信息,傳入實時MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情況的變化存在table[12][4]數(shù)組中
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);//要用到繪制函數(shù),所以先聲明
switch (get)//switch判斷用戶輸入的鍵盤信息
{
case 37: //左移,向左鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向左移動對應(yīng)的是哪種情況
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])
{
//找到對應(yīng)的情況后執(zhí)行以下語句
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時。
//遍歷繪制對應(yīng)的三個格子信息
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--;//繪制結(jié)束后,要改變MAN的實時位置信息,并break跳出循環(huán)
break;
}
break;//再次break跳出switch語句
case 38://上移,向上鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向上移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向右移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向下移動對應(yīng)的是哪種情況
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.最后,我們給窗口載入一張完美的背景圖片,至此就可以實現(xiàn)完整推箱子小游戲了。
實際效果圖:

效果圖-背景
最后整合的代碼就是:
/*
作者:DawsonLee
Email:dawsonlee1790@foxmail.com
*/
#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>
#define BLACK 0 //黑格:用于填充圖像
#define WHITEWALL 1 //白墻:用于阻擋主角移動
#define BLUEWALL 2 //藍(lán)格:用于表示可移動空間
#define BALL 3 //點:用于指定箱子放置位置
#define BOX 4 //箱子:用于表示初始箱子位置
#define REDBOX 5 //變色的箱子:用于表示這個點位置已經(jīng)放置箱子
#define MAN 6 //主角:用于表示主角位置
#define MANBALL 7 //主角站在點上
int main()
{
int map[13][16];//創(chuàng)建一個map數(shù)組用來存儲矩陣信息
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);//調(diào)用readmap()函數(shù)。
initgraph(800, 650);//生成一個寬800,高650的窗口。假設(shè)矩陣元素對應(yīng)的每個小矩形是50*50的,那個窗口就應(yīng)該是這么大。
//載入一張漂亮的背景圖片
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();//關(guān)閉窗口
return 0;
}
int readmap(int map[13][16], int &man_i, int &man_j)//map[13][16]是形參,其中&man_i表是的是man_i的引用,引用傳遞的意義在于:傳入?yún)?shù)會因函數(shù)中的操作而改變
{
FILE *fp = fopen("MAP.txt", "rb");//以只讀形式打開文件MAP.txt
if (!fp) {
printf("打開文件失敗,文件位置你可能放錯了\n");
exit(1);//打開失敗則結(jié)束程序
}
int i, j;
char str[10];//用于存儲從文本文件讀取的字符串信息
for (i = 0; i<13; i++)
for (j = 0; j < 16; j++)
{
fscanf(fp, "%s", str); //從文件中讀取一個字符串,遇到空格結(jié)束
map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎?,并賦值給map[i][j]
if (map[i][j] == MAN) //如果找到了MAN的位置,則返回坐標(biāo)在 man_i和 man_j 中
{
man_i = i;
man_j = j;
}
}
return 0;
}
/*
下面是在圖形庫繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識,C語言新手不必過多糾結(jié)不懂的東西。但要知道,創(chuàng)建的源文件要是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);
}
/*
傳入函數(shù)的參數(shù) get表示用戶輸入的鍵盤按鍵,傳入實時數(shù)組map的信息,傳入實時MAN的位置信息man_i,man_j。
*/
void move(char get, int map[13][16], int &man_i, int &man_j)
{
//首先把情況的變化存在table[12][4]數(shù)組中
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);//要用到繪制函數(shù),所以先聲明
switch (get)//switch判斷用戶輸入的鍵盤信息
{
case 37: //左移,向左鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向左移動對應(yīng)的是哪種情況
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])
{
//找到對應(yīng)的情況后執(zhí)行以下語句
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時。
//遍歷繪制對應(yīng)的三個格子信息
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--;//繪制結(jié)束后,要改變MAN的實時位置信息,并break跳出循環(huán)
break;
}
break;//再次break跳出switch語句
case 38://上移,向上鍵的ASCII碼
//for循環(huán)遍歷判斷MAN向上移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向右移動對應(yīng)的是哪種情況
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循環(huán)遍歷判斷MAN向下移動對應(yīng)的是哪種情況
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;
}
}