C語言推箱子小游戲教程


作者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;
    }
}

8.附上整個工程項目的文件

9.通過學(xué)習(xí),您還可以加上諸多功能,比如音樂的播放,用戶登陸和地圖的繪制等。下面給一個有上述功能的推箱子游戲

源碼版本

Release版本(可執(zhí)行文件 .exe)

項目展示視頻

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,224評論 3 119
  • 文明的最終形態(tài) 之前因為中國的天眼計劃跟室友進(jìn)行討論,聊到了如果外星人發(fā)現(xiàn)了我們,想要侵略我們該怎么辦?到底該不該...
    雪山上的來客閱讀 232評論 0 0
  • 1.簡述對JVM、JRE、JDK的理解 JVM:java虛擬機,一個模擬的計算機,相當(dāng)于計算機系統(tǒng)(硬件+軟件)J...
    GS的BLOG閱讀 212評論 0 0
  • 話說今天是我人品大爆發(fā)的日子,男神毛毛竟然大老遠(yuǎn)的跑來給我送鞋墊兒,哈哈,是我長的漂亮的原因么?果然美女和鞋墊兒更...
    渦孩緹閱讀 103評論 0 0
  • 淅淅瀝瀝的一場春雨潤澤了大地,雨過天晴,天藍(lán)樹綠花更艷了,灌了漿的莊稼開始了瘋長,天地間原本現(xiàn)出的灰頭土臉被雨...
    牧言1閱讀 215評論 0 0

友情鏈接更多精彩內(nèi)容