溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言利用循環(huán)鏈表功能制作一個貪吃蛇游戲

發(fā)布時間:2020-11-09 14:56:42 來源:億速云 閱讀:211 作者:Leah 欄目:開發(fā)技術

C語言利用循環(huán)鏈表功能制作一個貪吃蛇游戲?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

總體思想

利用循環(huán)鏈表將一條蛇的坐標進行存儲,然后利用gotoxy()函數(shù)(可以將光標定位到指定的位置),此時根據(jù)蛇的坐標進行輸出“@”,輸出多幾個既可以產(chǎn)生一條蛇。通過遍歷循環(huán)鏈表進行蛇的移動,對循環(huán)鏈表的插入元素,產(chǎn)生蛇變長的效果。下面為各功能實現(xiàn)的函數(shù)

1.貪吃蛇地圖函數(shù)map()
2.蛇的移動move(),up(),left()等函數(shù)
3.產(chǎn)生食物food()和吃到食物eat_food()
4.蛇吃到食物時產(chǎn)生的變長效果snake_link()函數(shù)
5.判斷蛇的死亡,分別為撞墻hit_wall()和自殺suicide()

1.貪吃蛇地圖函數(shù)map()
游戲地圖采用的是應該封閉的區(qū)域,采用一個數(shù)組a[25][50],將此數(shù)組初始化為0,將游戲墻的邊緣賦值為1,當數(shù)組為0,輸出" ",數(shù)組為1,輸出“#”,產(chǎn)生一個地圖。
代碼如下:

void map()   //創(chuàng)建蛇的地圖
{
    int a[25][50] = {0};
    int i,j;
    for(i = 0; i < 50; i++)
    {
        a[0][i] = 1;
        a[24][i] =1;
    }
    for(i = 0; i < 25; i++)
    {
        a[i][0] = 1;
        a[i][49] =1;
    }
    for(i = 0; i < 25; i++)
        for(j = 0; j < 50; j++)
        {
            if(j%50 == 0)
                printf("\n");
            if(a[i][j] == 0)
            {
                printf(" ");
            }
            else
            {
                printf("#");
            }
        }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2.蛇的移動move(),up(),left()等函數(shù)
move()函數(shù)主要對蛇的上下左右進行更改在此采用switch函數(shù)進行解決(下面代碼中ch為全局變量)
代碼如下

void move(struct snake *p)   //蛇的移動函數(shù)
{
    while(1)
    {
        ch = getch();
        switch(ch)
        {
        case 'W':p = up(p);break;
        case 'A':p = left(p);break;
        case 'D':p = right(p);break;
        case 'S':p = down(p);break;
        }
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
讓蛇動起來的即我們主要對蛇的坐標進行更改,此時蛇頭移動一次我們就利用gotoxy()函數(shù)進行輸出“@”,然后在蛇尾輸出“ ”,循環(huán)往復就可以產(chǎn)生蛇移動的效果,蛇的上下左右則只需在移動一個方向的時候?qū)我坏淖鴺藊或y進行更改,然后對更改的坐標保存進循環(huán)鏈表即可。移動函數(shù)則主要有up(),left()等,因為做法差不多,在此只對up()函數(shù)進行展示
代碼如下

struct snake *up(struct snake *p) //向上移動
{

    int x;
    int y;
    x = p->pre->x;                 //將蛇頭坐標賦值給x,y
    y = p->pre->y;
    while(p)                      //對循環(huán)鏈表的遍歷,即蛇的遍歷
    {
        Sleep(SNAKE_SPEED);        //蛇移動的速度
        y--;                       //向上移動則只需將縱坐標進行減,就可以實現(xiàn)蛇向上移動的效果
        gotoxy(p->x,p->y);         //定位到蛇尾,輸出“ ”即蛇尾消失
        printf(" ");
        gotoxy(x, y);              //定位到蛇頭輸出,"@",結(jié)合上面的蛇尾消失又進行蛇頭打印,產(chǎn)生蛇移動的效果
        printf("@");
        suicide(p,x,y);            //判斷蛇頭是否撞到蛇身
        p = p->next;               //將蛇頭的坐標變?yōu)橄乱粋€
        p->pre->x = x;             //此時將前一個蛇頭變成蛇尾,通過不斷的遍歷產(chǎn)生不斷移動的效果
        p->pre->y = y;
        food();                    //產(chǎn)生食物
        eat_food(p,x,y);           //判斷是否吃到食物
        hit_wall(y);               //判斷是否撞墻
        if(kbhit()) break;        //判斷是否有按鍵輸入,有就進行蛇移動方向的改變
    }

    return p;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
3.產(chǎn)生食物food()和吃到食物eat_food()
食物和吃到食物,產(chǎn)生食物則采用了產(chǎn)生隨機數(shù),產(chǎn)生一個食物的x,y坐標分別存放在全局變量food_xy[2]數(shù)組里面,最后利用gotoxy(food_xy[0],food_xy[1])隨機產(chǎn)生食物
代碼如下

void food()                       //產(chǎn)生食物
{
    int i;
    if(!flag)                     //根據(jù)flag的值來判斷地圖上是否有食物
    {
        srand( (unsigned)time( NULL ) );
        for( i = 0; i < 2; i++ )  //對food_(x,y)來隨機賦值
        {
            food_xy[i] = rand()%24+2;
            while(food_xy[0] == 1 || food_xy[0] == 25) //這兩個while為了防止食物
                food_xy[0] = rand()%24+2;             //的坐標與地圖的邊緣重疊
            while(food_xy[1] >= 49 || food_xy[1] == 1)
                food_xy[1] =rand()%24+2;
        }
        gotoxy(food_xy[0],food_xy[1]);  //打印食物
        printf("*");
        flag = 1;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
吃到食物eat_food(),則我們只需判斷蛇頭是否和食物的坐標重疊,若重疊則表明蛇吃到了食物
代碼如下

void eat_food(struct snake *p,int x, int y)           //蛇吃到食物,即主要是對蛇頭的x,y坐標和
{                                                     //food_xy的坐標進行匹配對比,若相同即調(diào)
    if(x == food_xy[0] && y == food_xy[1])            //snake_link函數(shù)即可
    {
        p = snake_link(p);
        flag = 0;                                     //表明食物被吃,準備重新產(chǎn)生食物
        printSnake(p);
        gotoxy(8,0);
        score = score + 1;                            //得分
        printf("%d",score);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
4.蛇吃到食物時產(chǎn)生的變長效果snake_link()函數(shù)
蛇的變長,當蛇吃到食物的時候,此時我們將食物的坐標變成蛇頭,然后進行重新的打印蛇,即可以有蛇變成的效果產(chǎn)生,實質(zhì)為對循環(huán)鏈表進行元素的插入。
在這里插入圖片描述
即通過這樣將食物的坐標插進去循環(huán)鏈表,達到蛇變成的效果
代碼如下

struct snake *snake_link(struct snake *p)      //蛇的連接
{
    struct snake *q;
    q = (struct snake *)malloc(sizeof(struct snake)); //即主要是實現(xiàn)了對循環(huán)鏈表的插入元素,再
    q->x = food_xy[0];                                //進行打印蛇,即可有吃到食物蛇變長的結(jié)果
    q->y = food_xy[1];
    q->pre = p->pre;
    p->pre->next = q;
    p->pre = q;
    q->next = p;
    return p;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
5.判斷蛇的死亡,分別為撞墻hit_wall()和自殺suicide()
撞墻,則只需判斷蛇頭的單一坐標x軸或者y軸是否與墻壁的坐標是否相等,若相等則說明蛇撞墻了
代碼如下

void hit_wall(int n)       //判斷蛇是否撞墻,即對蛇的單一坐標x或者y進行判斷,若等于墻壁的值,即游戲結(jié)束
{
    if(ch == 'W'|| ch == 'S' )
        if(n == 1 || n == 25)              //墻壁的坐標值
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }
    if(ch == 'A'|| ch == 'D' )
        if(n == 0 || n == 49)
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
自殺suicide()即蛇頭是否有撞到了蛇身,做法是把蛇頭的坐標拿出來,與蛇身的坐標進行對比如果相等,說明蛇頭撞到了蛇身,本質(zhì)上是循環(huán)鏈表的值進行匹配,遍歷
代碼如下

void suicide(struct snake *p, int x, int y) //自殺,即撞到自己本身的時候游戲結(jié)束
{
    struct snake *q;                         //把蛇頭坐標傳遞進來,然后與其自己身體坐標做對比若有相等則表明,蛇頭撞到了蛇身
    q = p;
    while(q != p->next)                      //即對循環(huán)鏈表的遍歷匹配
    {
        if(p->x == x && p->y == y)
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }
        else
            p = p->next;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
到此蛇的基本功能已經(jīng)講完,以下是全部代碼。

全部代碼如下

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#define SNAKE_SPEED 200 //蛇移動的速度
int score = 0;         //成績得分
int flag = 0;          //用于判斷地圖上是否存在食物,0為不存在食物
int food_xy[2];         //定位食物的位置
char ch;               //用來決定蛇的移動方向
struct snake   //定義一條循環(huán)鏈表的蛇
{
    int x;
    int y;
    struct snake *next;
    struct snake *pre;
};

void HideCursor()//把蛇移動的時候產(chǎn)生的光標進行隱藏,隱藏光標函數(shù)
{
 CONSOLE_CURSOR_INFO cursor;
 cursor.bVisible = FALSE;
 cursor.dwSize = sizeof(cursor);
 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
 SetConsoleCursorInfo(handle, &cursor);
}

void gotoxy(int x, int y)   //定位光標函數(shù),用來實現(xiàn)蛇的移動,和食物的出現(xiàn)(傳送x,y可以將光標定位到x,y)
{
    HideCursor();
    COORD coord = {x,y};
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

void map()   //創(chuàng)建蛇的地圖
{
    int a[25][50] = {0};
    int i,j;
    for(i = 0; i < 50; i++)
    {
        a[0][i] = 1;
        a[24][i] =1;
    }
    for(i = 0; i < 25; i++)
    {
        a[i][0] = 1;
        a[i][49] =1;
    }
    for(i = 0; i < 25; i++)
        for(j = 0; j < 50; j++)
        {
            if(j%50 == 0)
                printf("\n");
            if(a[i][j] == 0)
            {
                printf(" ");
            }
            else
            {
                printf("#");
            }
        }
}

struct snake *createSnake()   //給蛇進行初始化,構(gòu)建一條蛇,本質(zhì)為循環(huán)鏈表
{
    int i;
    struct snake *head,*p,*q;
    p = q = (struct snake *)malloc(sizeof(struct snake));
    head = NULL;
    head = p;
    head->pre = NULL;
    for( i = 0; i < 5; i++)
    {
        p->x = 25 - i;
        p->y = 13;
        p->pre = head->pre;
        head->pre = p;
        q->next = p;
        q = p;
        p = (struct snake *)malloc(sizeof(struct snake));
    }
    q->next = head;
    return head;

}

void printSnake(struct snake *p)   //打印蛇,利用gotoxy()來對蛇進行打印,只需遍歷一次循環(huán)鏈表即可將坐標可視化為一條蛇
{
    struct snake *q;
    q = p;
    while(q != p->next)             //循環(huán)鏈表的遍歷
    {
        gotoxy(p->x,p->y);          //根據(jù)坐標和定位光標函數(shù)來打@,實現(xiàn)輸出蛇
        printf("@");
        p = p->next;
    }
    gotoxy(p->x,p->y);
    printf("@");
    gotoxy(0,0);
    printf("你的得分:");          //初始化得分
}

void food()                       //產(chǎn)生食物
{
    int i;
    if(!flag)                     //根據(jù)flag的值來判斷地圖上是否有食物
    {
        srand( (unsigned)time( NULL ) );
        for( i = 0; i < 2; i++ )  //對food_(x,y)來隨機賦值
        {
            food_xy[i] = rand()%24+2;
            while(food_xy[0] == 1 || food_xy[0] == 25) //這兩個while為了防止食物的坐標與地圖的邊緣重疊
                food_xy[0] = rand()%24+2;
            while(food_xy[1] >= 49 || food_xy[1] == 1)
                food_xy[1] =rand()%24+2;
        }
        gotoxy(food_xy[0],food_xy[1]);  //打印食物
        printf("*");
        flag = 1;
    }
}

struct snake *snake_link(struct snake *p)      //蛇的連接
{
    struct snake *q;
    q = (struct snake *)malloc(sizeof(struct snake)); //即主要是實現(xiàn)了對循環(huán)鏈表的插入元素,再進行打印蛇,即可有吃到食物蛇變長的結(jié)果
    q->x = food_xy[0];
    q->y = food_xy[1];
    q->pre = p->pre;
    p->pre->next = q;
    p->pre = q;
    q->next = p;
    return p;
}

void eat_food(struct snake *p,int x, int y)           //蛇吃到食物,即主要是對蛇頭的x,y坐標和food_xy的坐標進行匹配對比,若相同即調(diào)用snake_link函數(shù)即可
{
    if(x == food_xy[0] && y == food_xy[1])
    {
        p = snake_link(p);
        flag = 0;
        printSnake(p);
        gotoxy(8,0);
        score = score + 1;
        printf("%d",score);
    }
}

void hit_wall(int n)       //判斷蛇是否撞墻,即對蛇的單一坐標x或者y進行判斷,若等于墻壁的值,即游戲結(jié)束
{
    if(ch == 'W'|| ch == 'S' )
        if(n == 1 || n == 25)
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }
    if(ch == 'A'|| ch == 'D' )
        if(n == 0 || n == 49)
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }
}


void suicide(struct snake *p, int x, int y) //自殺,即撞到自己本身的時候游戲結(jié)束
{
    struct snake *q;                         //把蛇頭坐標傳遞進來,然后與其自己身體坐標做對比若有相等則表明,蛇頭撞到了蛇身
    q = p;
    while(q != p->next)                      //即對循環(huán)鏈表的遍歷匹配
    {
        if(p->x == x && p->y == y)
        {
            gotoxy(0,26);
            printf("游戲結(jié)束!");
            printf("你的得分:%d",score);
            exit(0);
        }

        else
            p = p->next;
    }
}

struct snake *up(struct snake *p) //向上移動
{

    int x;
    int y;
    x = p->pre->x;                 //將蛇頭坐標賦值給x,y
    y = p->pre->y;
    while(p)                      //對循環(huán)鏈表的遍歷,即蛇的遍歷
    {

        Sleep(SNAKE_SPEED);        //蛇移動的速度
        y--;                       //向上移動則只需將縱坐標進行減,就可以實現(xiàn)蛇向上移動的效果
        gotoxy(p->x,p->y);         //定位到蛇尾,輸出“ ”即蛇尾消失
        printf(" ");
        gotoxy(x, y);              //定位到蛇頭輸出,"@",結(jié)合上面的蛇尾消失又進行蛇頭打印,產(chǎn)生蛇移動的效果
        printf("@");
        suicide(p,x,y);            //判斷蛇頭是否撞到蛇身
        p = p->next;               //將蛇頭的坐標變?yōu)橄乱粋€
        p->pre->x = x;             //此時將前一個蛇頭變成蛇尾,通過不斷的遍歷產(chǎn)生不斷移動的效果
        p->pre->y = y;
        food();                    //產(chǎn)生食物
        eat_food(p,x,y);           //判斷是否吃到食物
        hit_wall(y);               //判斷是否撞墻
        if(kbhit()) break;        //判斷是否有按鍵輸入,有就進行蛇移動方向的改變
    }

    return p;


}

struct snake *left(struct snake *p) //向左移動
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

        Sleep(SNAKE_SPEED);
        x--;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(x);
        if(kbhit()) break;
    }
    return p;
}

struct snake *down(struct snake *p)  //向下移動
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

        Sleep(SNAKE_SPEED);
        y++;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(y);
        if(kbhit()) break;
    }
    return p;
}

struct snake *right(struct snake *p)   //向右移動
{
    int x;
    int y;
    x = p->pre->x;
    y = p->pre->y;
    while(p)
    {

        Sleep(SNAKE_SPEED);
        x++;
        gotoxy(p->x,p->y);
        printf(" ");
        gotoxy(x, y);
        printf("@");
        suicide(p,x,y);
        p = p->next;
        p->pre->x = x;
        p->pre->y = y;
        food();
        eat_food(p,x,y);
        hit_wall(x);
        if(kbhit()) break;
    }
    return p;


}
void move(struct snake *p)   //蛇的移動函數(shù)
{
    while(1)
    {
        ch = getch();
        switch(ch)
        {
        case 'W':p = up(p);break;
        case 'A':p = left(p);break;
        case 'D':p = right(p);break;
        case 'S':p = down(p);break;
        }
    }
}
int main()
{
    struct snake *p;
    map();      //產(chǎn)生地圖
    p = createSnake(); // 初始化蛇
    printSnake(p);   // 打印蛇
    move(p);        //移動蛇

    return 0;
}

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業(yè)資訊頻道,感謝您對億速云的支持。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI