C語(yǔ)言推箱子小游戲教程


作者GitHub-Pages個(gè)人主頁(yè)
本教程GitHub-Pages鏈接
本教程百度云下載地址
本教程編寫于2016/11/22
Dawson Lee edited this page on Beijing, 2018/7/3


設(shè)計(jì)思路

將整個(gè)畫面分成13*16的矩陣,每個(gè)元素對(duì)應(yīng)者一個(gè)小矩形。然后用0代表黑格桑李,1代表白墻,2代表藍(lán)格……娜氏,這樣就有了整幅圖像的信息。然后移動(dòng)就可以想象成墩新,改變矩陣的坐標(biāo)信息贸弥,形成一個(gè)新的矩陣,再重繪海渊。這就是推箱子的基本原理绵疲。

#define BLACK         0 //黑格:用于填充圖像
#define WHITEWALL     1 //白墻:用于阻擋主角移動(dòng)
#define BLUEWALL      2 //藍(lán)格:用于表示可移動(dòng)空間
#define BALL          3 //點(diǎn):用于指定箱子放置位置
#define BOX       4 //箱子:用于表示初始箱子位置
#define REDBOX        5 //變色的箱子:用于表示這個(gè)點(diǎn)位置已經(jīng)放置箱子
#define MAN       6 //主角:用于表示主角位置
#define MANBALL       7 //主角站在點(diǎn)上
設(shè)計(jì)思路

步驟

1.編譯環(huán)境:Visual Studio Community 2015

Tip:

  • 您也可以自行百度或者google Visual Studio Community 2015的其它下載途徑
  • 您也可以嘗試使用Visual Studio其它版本,但有可能會(huì)出現(xiàn)未知問題

2.要給VS2015安裝EGE圖形庫(kù)

3.要參考EGE圖形庫(kù)幫助文檔

Tip:如果鏈接失效切省,請(qǐng)自行百度或者google"EGE圖形庫(kù)幫助文檔"

4.剛才我們說到最岗,圖像的背后對(duì)應(yīng)著一個(gè)矩陣,我們可以考慮將矩陣的信息存儲(chǔ)在一個(gè)MAP.txt文件中朝捆,在程序運(yùn)行時(shí)讀取般渡。下面我來介紹,在文件中讀取一個(gè)矩陣芙盘。

首先我們得有一個(gè)TXT文件:MAP.txt(一定確保路徑放置正確),它存儲(chǔ)著這樣一個(gè)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("打開文件失敗驯用,文件位置你可能放錯(cuò)了\n");
        exit(1);
    }
    int map[13][16];//創(chuàng)建一個(gè)map數(shù)組用來存儲(chǔ)矩陣信息
    int i, j;
    char str[10];//用于存儲(chǔ)從文本文件讀取的字符串信息
    for (i = 0; i<13; i++)
        for (j = 0; j < 16; j++) {
            fscanf(fp, "%s", str); //從文件中讀取一個(gè)字符串,遇到空格結(jié)束
            map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎腿謇希①x值給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文件的讀取矩陣的功能蝴乔,寫在一個(gè)readmap()函數(shù)中,實(shí)現(xiàn)功能的模塊化驮樊。并加多一項(xiàng)功能薇正,就是查找出片酝,MAN的位置。

//map[13][16]是形參挖腰,其中&man_i表是的是man_i的引用雕沿,引用傳遞的意義在于:傳入?yún)?shù)會(huì)因函數(shù)中的操作而改變
int readmap(int map[13][16], int &man_i, int &man_j)
{
    FILE *fp = fopen("MAP.txt", "rb");//以只讀形式打開文件MAP.txt
    if (!fp) {
        printf("打開文件失敗,文件位置你可能放錯(cuò)了\n");
        exit(1);//打開失敗則結(jié)束程序
    }
    int i, j;
    char str[10];//用于存儲(chǔ)從文本文件讀取的字符串信息
    for (i = 0; i<13; i++)
        for (j = 0; j < 16; j++) 
        {
            fscanf(fp, "%s", str); //從文件中讀取一個(gè)字符串猴仑,遇到空格結(jié)束
            map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎蜕舐郑①x值給map[i][j]
            if (map[i][j] == MAN) //如果找到了MAN的位置,則返回坐標(biāo)在 man_i和 man_j 中
            {
                man_i = i;
                man_j = j;
            }
        }
    return 0;
}

5.接下來我們實(shí)現(xiàn)在窗口中辽俗,把矩陣信息轉(zhuǎn)變成圖像疾渣。原理就是,將圖片貼在窗口上崖飘。

  • 圖片資源pic.zip(把當(dāng)中的pic文件夾解壓榴捡,存放在正確路徑中,如果路徑不正確會(huì)導(dǎo)致窗口中沒有圖像)

實(shí)現(xiàn)的效果如圖所示:

效果圖-無背景

繪制操作的源代碼:

#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>

#define BLACK         0 //黑格:用于填充圖像
#define WHITEWALL     1 //白墻:用于阻擋主角移動(dòng)
#define BLUEWALL      2 //藍(lán)格:用于表示可移動(dòng)空間
#define BALL          3 //點(diǎn):用于指定箱子放置位置
#define BOX       4 //箱子:用于表示初始箱子位置
#define REDBOX        5 //變色的箱子:用于表示這個(gè)點(diǎn)位置已經(jīng)放置箱子
#define MAN       6 //主角:用于表示主角位置
#define MANBALL       7 //主角站在點(diǎn)上

int main()
{
    int map[13][16];//創(chuàng)建一個(gè)map數(shù)組用來存儲(chǔ)矩陣信息
    int man_i, man_j;//用來存儲(chǔ)人物的位置信息
    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);//生成一個(gè)寬800薄疚,高650的窗口碧信。假設(shè)矩陣元素對(duì)應(yīng)的每個(gè)小矩形是50*50的赊琳,那個(gè)窗口就應(yīng)該是這么大。
    for (int i = 0; i<13; i++)
        for (int j = 0; j < 16; j++)
        {
            darm(map[i][j], i, j);//遍歷繪制每個(gè)小矩形
        }

    getch();//等待一個(gè)鍵盤輸入砰碴,如果沒有的話躏筏,窗口會(huì)看不到,因?yàn)槌绦蜻\(yùn)行結(jié)束就會(huì)關(guān)閉窗口呈枉。生成關(guān)閉就轉(zhuǎn)瞬即逝
    closegraph();//關(guān)閉窗口
    return 0;
}

//map[13][16]是形參趁尼,其中&man_i表是的是man_i的引用,引用傳遞的意義在于:傳入?yún)?shù)會(huì)因函數(shù)中的操作而改變
int readmap(int map[13][16], int &man_i, int &man_j)
{
    FILE *fp = fopen("MAP.txt", "rb");//以只讀形式打開文件MAP.txt
    if (!fp) {
        printf("打開文件失敗猖辫,文件位置你可能放錯(cuò)了\n");
        exit(1);//打開失敗則結(jié)束程序
    }
    int i, j;
    char str[10];//用于存儲(chǔ)從文本文件讀取的字符串信息
    for (i = 0; i<13; i++)
        for (j = 0; j < 16; j++) 
        {
            fscanf(fp, "%s", str); //從文件中讀取一個(gè)字符串酥泞,遇到空格結(jié)束
            map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎停①x值給map[i][j]
            if (map[i][j] == MAN) //如果找到了MAN的位置啃憎,則返回坐標(biāo)在 man_i和 man_j 中
            {
                man_i = i;
                man_j = j;
            }
        }
    return 0;
}


/*
下面是在圖形庫(kù)繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識(shí)芝囤,C語(yǔ)言新手不必過多糾結(jié)不懂的東西。但要知道辛萍,創(chuàng)建的源文件要是cpp格式的
*/
void darm(int a, int ii, int jj)
{
    PIMAGE img;//聲明
    img = newimage();//實(shí)例化
    switch (a)
    {
    case BLACK:break;
    case WHITEWALL:
    {
        getimage(img, "pic/墻.jpg");//getimage()和putimage請(qǐng)翻閱ege圖形庫(kù)幫助手冊(cè)悯姊。
        putimage(jj * 50, ii * 50, img);//在ii行jj列繪制一個(gè)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.實(shí)現(xiàn)圖像的繪制以后那我們就應(yīng)該實(shí)現(xiàn)圖像的移動(dòng)了。

向右移動(dòng)

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

數(shù)組table

然后就可以開始寫move()函數(shù)辉阶,實(shí)現(xiàn)MAN的移動(dòng)先壕。move()函數(shù)源代碼

/*
傳入函數(shù)的參數(shù) get表示用戶輸入的鍵盤按鍵瘩扼,傳入實(shí)時(shí)數(shù)組map的信息,傳入實(shí)時(shí)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向左移動(dòng)對(duì)應(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])
            {
                //找到對(duì)應(yīng)的情況后執(zhí)行以下語(yǔ)句

                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];//如果不需要改變第三個(gè)格子的圖像倒慧,就不賦值。也就是如果table[i][3]==-1時(shí)包券。

                //遍歷繪制對(duì)應(yīng)的三個(gè)格子信息
                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的實(shí)時(shí)位置信息,并break跳出循環(huán)
                break;
            }
        break;//再次break跳出switch語(yǔ)句
    case 38://上移溅固,向上鍵的ASCII碼
        //for循環(huán)遍歷判斷MAN向上移動(dòng)對(duì)應(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向右移動(dòng)對(duì)應(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向下移動(dòng)對(duì)應(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ù)后侍郭,我們就可以實(shí)現(xiàn)推箱子的功能了询吴。整合后的源代碼:

#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>

#define BLACK         0 //黑格:用于填充圖像
#define WHITEWALL     1 //白墻:用于阻擋主角移動(dòng)
#define BLUEWALL      2 //藍(lán)格:用于表示可移動(dòng)空間
#define BALL          3 //點(diǎn):用于指定箱子放置位置
#define BOX       4 //箱子:用于表示初始箱子位置
#define REDBOX        5 //變色的箱子:用于表示這個(gè)點(diǎn)位置已經(jīng)放置箱子
#define MAN       6 //主角:用于表示主角位置
#define MANBALL       7 //主角站在點(diǎn)上

int main()
{
    int map[13][16];//創(chuàng)建一個(gè)map數(shù)組用來存儲(chǔ)矩陣信息
    int man_i, man_j;//用來存儲(chǔ)人物的位置信息
    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);//生成一個(gè)寬800亮元,高650的窗口猛计。假設(shè)矩陣元素對(duì)應(yīng)的每個(gè)小矩形是50*50的,那個(gè)窗口就應(yīng)該是這么大爆捞。
    for (int i = 0; i<13; i++)
        for (int j = 0; j < 16; j++)
        {
            darm(map[i][j], i, j);//遍歷繪制每個(gè)小矩形
        }

    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ù)會(huì)因函數(shù)中的操作而改變
int readmap(int map[13][16], int &man_i, int &man_j)
{
    FILE *fp = fopen("MAP.txt", "rb");//以只讀形式打開文件MAP.txt
    if (!fp) {
        printf("打開文件失敗盗温,文件位置你可能放錯(cuò)了\n");
        exit(1);//打開失敗則結(jié)束程序
    }
    int i, j;
    char str[10];//用于存儲(chǔ)從文本文件讀取的字符串信息
    for (i = 0; i<13; i++)
        for (j = 0; j < 16; j++) 
        {
            fscanf(fp, "%s", str); //從文件中讀取一個(gè)字符串,遇到空格結(jié)束
            map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎统芍猓①x值給map[i][j]
            if (map[i][j] == MAN) //如果找到了MAN的位置卖局,則返回坐標(biāo)在 man_i和 man_j 中
            {
                man_i = i;
                man_j = j;
            }
        }
    return 0;
}
/*
下面是在圖形庫(kù)繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識(shí),C語(yǔ)言新手不必過多糾結(jié)不懂的東西双霍。但要知道砚偶,創(chuàng)建的源文件要是cpp格式的
*/

void darm(int a, int ii, int jj)
{
    PIMAGE img;//聲明
    img = newimage();//實(shí)例化
    switch (a)
    {
    case BLACK:break;
    case WHITEWALL:
    {
        getimage(img, "pic/墻.jpg");//getimage()和putimage請(qǐng)翻閱ege圖形庫(kù)幫助手冊(cè)。
        putimage(jj * 50, ii * 50, img);//在ii行jj列繪制一個(gè)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í)時(shí)數(shù)組map的信息蟹演,傳入實(shí)時(shí)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向左移動(dòng)對(duì)應(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])
            {
                //找到對(duì)應(yīng)的情況后執(zhí)行以下語(yǔ)句

                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];//如果不需要改變第三個(gè)格子的圖像鸣个,就不賦值羞反。也就是如果table[i][3]==-1時(shí)布朦。

                //遍歷繪制對(duì)應(yīng)的三個(gè)格子信息
                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的實(shí)時(shí)位置信息昼窗,并break跳出循環(huán)
                break;
            }
        break;//再次break跳出switch語(yǔ)句
    case 38://上移是趴,向上鍵的ASCII碼
        //for循環(huán)遍歷判斷MAN向上移動(dòng)對(duì)應(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向右移動(dòng)對(duì)應(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向下移動(dòng)對(duì)應(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.最后唆途,我們給窗口載入一張完美的背景圖片,至此就可以實(shí)現(xiàn)完整推箱子小游戲了掸驱。

實(shí)際效果圖:


效果圖-背景

最后整合的代碼就是:

/*
作者:DawsonLee
Email:dawsonlee1790@foxmail.com
*/


#include<stdio.h>
#include<stdlib.h>
#include<graphics.h>

#define BLACK         0 //黑格:用于填充圖像
#define WHITEWALL     1 //白墻:用于阻擋主角移動(dòng)
#define BLUEWALL      2 //藍(lán)格:用于表示可移動(dòng)空間
#define BALL          3 //點(diǎn):用于指定箱子放置位置
#define BOX       4 //箱子:用于表示初始箱子位置
#define REDBOX        5 //變色的箱子:用于表示這個(gè)點(diǎn)位置已經(jīng)放置箱子
#define MAN       6 //主角:用于表示主角位置
#define MANBALL       7 //主角站在點(diǎn)上




int main()
{
    int map[13][16];//創(chuàng)建一個(gè)map數(shù)組用來存儲(chǔ)矩陣信息
    int man_i, man_j;//用來存儲(chǔ)人物的位置信息
    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);//生成一個(gè)寬800,高650的窗口毕贼。假設(shè)矩陣元素對(duì)應(yīng)的每個(gè)小矩形是50*50的温赔,那個(gè)窗口就應(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);//遍歷繪制每個(gè)小矩形
        }

    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ù)會(huì)因函數(shù)中的操作而改變
{
    FILE *fp = fopen("MAP.txt", "rb");//以只讀形式打開文件MAP.txt
    if (!fp) {
        printf("打開文件失敗待秃,文件位置你可能放錯(cuò)了\n");
        exit(1);//打開失敗則結(jié)束程序
    }
    int i, j;
    char str[10];//用于存儲(chǔ)從文本文件讀取的字符串信息
    for (i = 0; i<13; i++)
        for (j = 0; j < 16; j++) 
        {
            fscanf(fp, "%s", str); //從文件中讀取一個(gè)字符串拜秧,遇到空格結(jié)束
            map[i][j] = atoi(str);//將字符串轉(zhuǎn)變?yōu)檎停①x值給map[i][j]
            if (map[i][j] == MAN) //如果找到了MAN的位置锥余,則返回坐標(biāo)在 man_i和 man_j 中
            {
                man_i = i;
                man_j = j;
            }
        }
    return 0;
}
/*
下面是在圖形庫(kù)繪制小矩形中圖像的功能模塊
這部分涉及C++中的知識(shí)腹纳,C語(yǔ)言新手不必過多糾結(jié)不懂的東西痢掠。但要知道驱犹,創(chuàng)建的源文件要是cpp格式的
*/

void darm(int a, int ii, int jj)
{
    PIMAGE img;//聲明
    img = newimage();//實(shí)例化
    switch (a)
    {
    case BLACK:break;
    case WHITEWALL:
    {
        getimage(img, "pic/墻.jpg");//getimage()和putimage請(qǐng)翻閱ege圖形庫(kù)幫助手冊(cè)。
        putimage(jj * 50, ii * 50, img);//在ii行jj列繪制一個(gè)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í)時(shí)數(shù)組map的信息雄驹,傳入實(shí)時(shí)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向左移動(dòng)對(duì)應(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])
            {
                //找到對(duì)應(yīng)的情況后執(zhí)行以下語(yǔ)句

                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];//如果不需要改變第三個(gè)格子的圖像象缀,就不賦值蔬将。也就是如果table[i][3]==-1時(shí)。

                //遍歷繪制對(duì)應(yīng)的三個(gè)格子信息
                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的實(shí)時(shí)位置信息霞怀,并break跳出循環(huán)
                break;
            }
        break;//再次break跳出switch語(yǔ)句
    case 38://上移,向上鍵的ASCII碼
        //for循環(huán)遍歷判斷MAN向上移動(dòng)對(duì)應(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向右移動(dòng)對(duì)應(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向下移動(dòng)對(duì)應(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.附上整個(gè)工程項(xiàng)目的文件

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

源碼版本

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

項(xiàng)目展示視頻

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市滤灯,隨后出現(xiàn)的幾起案子坪稽,更是在濱河造成了極大的恐慌,老刑警劉巖鳞骤,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件刽漂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弟孟,警方通過查閱死者的電腦和手機(jī)贝咙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拂募,“玉大人庭猩,你說我怎么就攤上這事〕轮ⅲ” “怎么了蔼水?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)录肯。 經(jīng)常有香客問我趴腋,道長(zhǎng),這世上最難降的妖魔是什么论咏? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任优炬,我火速辦了婚禮,結(jié)果婚禮上厅贪,老公的妹妹穿的比我還像新娘蠢护。我一直安慰自己,他們只是感情好养涮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布葵硕。 她就那樣靜靜地躺著,像睡著了一般贯吓。 火紅的嫁衣襯著肌膚如雪懈凹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天悄谐,我揣著相機(jī)與錄音介评,去河邊找鬼。 笑死尊沸,一個(gè)胖子當(dāng)著我的面吹牛威沫,可吹牛的內(nèi)容都是我干的贤惯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼棒掠,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼孵构!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烟很,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤颈墅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后雾袱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恤筛,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年芹橡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毒坛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡林说,死狀恐怖煎殷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腿箩,我是刑警寧澤豪直,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站珠移,受9級(jí)特大地震影響弓乙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钧惧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一暇韧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧垢乙,春花似錦锨咙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)粹舵。三九已至钮孵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眼滤,已是汗流浹背巴席。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留诅需,地道東北人漾唉。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓荧库,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親赵刑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子分衫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請(qǐng)求組件 FMDB本地?cái)?shù)據(jù)庫(kù)組件 SD...
    陽(yáng)明先生_X自主閱讀 15,979評(píng)論 3 119
  • 文明的最終形態(tài) 之前因?yàn)橹袊?guó)的天眼計(jì)劃跟室友進(jìn)行討論般此,聊到了如果外星人發(fā)現(xiàn)了我們蚪战,想要侵略我們?cè)撛趺崔k?到底該不該...
    雪山上的來客閱讀 162評(píng)論 0 0
  • 1.簡(jiǎn)述對(duì)JVM铐懊、JRE邀桑、JDK的理解 JVM:java虛擬機(jī),一個(gè)模擬的計(jì)算機(jī)科乎,相當(dāng)于計(jì)算機(jī)系統(tǒng)(硬件+軟件)J...
    GS的BLOG閱讀 197評(píng)論 0 0
  • 話說今天是我人品大爆發(fā)的日子壁畸,男神毛毛竟然大老遠(yuǎn)的跑來給我送鞋墊兒,哈哈茅茂,是我長(zhǎng)的漂亮的原因么瓤摧?果然美女和鞋墊兒更...
    渦孩緹閱讀 83評(píng)論 0 0
  • 淅淅瀝瀝的一場(chǎng)春雨潤(rùn)澤了大地,雨過天晴玉吁,天藍(lán)樹綠花更艷了照弥,灌了漿的莊稼開始了瘋長(zhǎng),天地間原本現(xiàn)出的灰頭土臉被雨...
    牧言1閱讀 158評(píng)論 0 0