C語(yǔ)言循環(huán)鏈表實(shí)現(xiàn)貪吃蛇游戲
本文實(shí)例為大家分享了C語(yǔ)言表實(shí)現(xiàn)貪吃蛇游戲的具體代碼,供大家參考,具體內(nèi)容如下
總體思想
利用循環(huán)鏈表將一條蛇的坐標(biāo)進(jìn)行存儲(chǔ),然后利用gotoxy()函數(shù)(可以將光標(biāo)定位到指定的位置),此時(shí)根據(jù)蛇的坐標(biāo)進(jìn)行輸出“@”,輸出多幾個(gè)既可以產(chǎn)生一條蛇。通過(guò)遍歷循環(huán)鏈表進(jìn)行蛇的移動(dòng),對(duì)循環(huán)鏈表的插入元素,產(chǎn)生蛇變長(zhǎng)的效果。下面為各功能實(shí)現(xiàn)的函數(shù)
1.貪吃蛇地圖函數(shù)map()
2.蛇的移動(dòng)move(),up(),left()等函數(shù)
3.產(chǎn)生食物food()和吃到食物eat_food()
4.蛇吃到食物時(shí)產(chǎn)生的變長(zhǎng)效果snake_link()函數(shù)
5.判斷蛇的死亡,分別為撞墻hit_wall()和自殺suicide()
1.貪吃蛇地圖函數(shù)map()
游戲地圖采用的是應(yīng)該封閉的區(qū)域,采用一個(gè)數(shù)組a[25][50],將此數(shù)組初始化為0,將游戲墻的邊緣賦值為1,當(dāng)數(shù)組為0,輸出" ",數(shù)組為1,輸出“#”,產(chǎn)生一個(gè)地圖。
代碼如下:
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("#"); } } }
2.蛇的移動(dòng)move(),up(),left()等函數(shù)
move()函數(shù)主要對(duì)蛇的上下左右進(jìn)行更改在此采用switch函數(shù)進(jìn)行解決(下面代碼中ch為全局變量)
代碼如下
void move(struct snake *p) //蛇的移動(dòng)函數(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; } } }
讓蛇動(dòng)起來(lái)的即我們主要對(duì)蛇的坐標(biāo)進(jìn)行更改,此時(shí)蛇頭移動(dòng)一次我們就利用gotoxy()函數(shù)進(jìn)行輸出“@”,然后在蛇尾輸出“ ”,循環(huán)往復(fù)就可以產(chǎn)生蛇移動(dòng)的效果,蛇的上下左右則只需在移動(dòng)一個(gè)方向的時(shí)候?qū)我坏淖鴺?biāo)x或y進(jìn)行更改,然后對(duì)更改的坐標(biāo)保存進(jìn)循環(huán)鏈表即可。移動(dòng)函數(shù)則主要有up(),left()等,因?yàn)樽龇ú畈欢?在此只對(duì)up()函數(shù)進(jìn)行展示
代碼如下
struct snake *up(struct snake *p) //向上移動(dòng) { int x; int y; x = p->pre->x; //將蛇頭坐標(biāo)賦值給x,y y = p->pre->y; while(p) //對(duì)循環(huán)鏈表的遍歷,即蛇的遍歷 { Sleep(SNAKE_SPEED); //蛇移動(dòng)的速度 y--; //向上移動(dòng)則只需將縱坐標(biāo)進(jìn)行減,就可以實(shí)現(xiàn)蛇向上移動(dòng)的效果 gotoxy(p->x,p->y); //定位到蛇尾,輸出“ ”即蛇尾消失 printf(" "); gotoxy(x, y); //定位到蛇頭輸出,"@",結(jié)合上面的蛇尾消失又進(jìn)行蛇頭打印,產(chǎn)生蛇移動(dòng)的效果 printf("@"); suicide(p,x,y); //判斷蛇頭是否撞到蛇身 p = p->next; //將蛇頭的坐標(biāo)變?yōu)橄乱粋€(gè) p->pre->x = x; //此時(shí)將前一個(gè)蛇頭變成蛇尾,通過(guò)不斷的遍歷產(chǎn)生不斷移動(dòng)的效果 p->pre->y = y; food(); //產(chǎn)生食物 eat_food(p,x,y); //判斷是否吃到食物 hit_wall(y); //判斷是否撞墻 if(kbhit()) break; //判斷是否有按鍵輸入,有就進(jìn)行蛇移動(dòng)方向的改變 } return p; }
3.產(chǎn)生食物food()和吃到食物eat_food()
食物和吃到食物,產(chǎn)生食物則采用了產(chǎn)生隨機(jī)數(shù),產(chǎn)生一個(gè)食物的x,y坐標(biāo)分別存放在全局變量food_xy[2]數(shù)組里面,最后利用gotoxy(food_xy[0],food_xy[1])隨機(jī)產(chǎn)生食物
代碼如下
void food() //產(chǎn)生食物 { int i; if(!flag) //根據(jù)flag的值來(lái)判斷地圖上是否有食物 { srand( (unsigned)time( NULL ) ); for( i = 0; i < 2; i++ ) //對(duì)food_(x,y)來(lái)隨機(jī)賦值 { food_xy[i] = rand()%24+2; while(food_xy[0] == 1 || food_xy[0] == 25) //這兩個(gè)while為了防止食物 food_xy[0] = rand()%24+2; //的坐標(biāo)與地圖的邊緣重疊 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; } }
吃到食物eat_food(),則我們只需判斷蛇頭是否和食物的坐標(biāo)重疊,若重疊則表明蛇吃到了食物
代碼如下
void eat_food(struct snake *p,int x, int y) //蛇吃到食物,即主要是對(duì)蛇頭的x,y坐標(biāo)和 { //food_xy的坐標(biāo)進(jìn)行匹配對(duì)比,若相同即調(diào) if(x == food_xy[0] && y == food_xy[1]) //snake_link函數(shù)即可 { p = snake_link(p); flag = 0; //表明食物被吃,準(zhǔn)備重新產(chǎn)生食物 printSnake(p); gotoxy(8,0); score = score + 1; //得分 printf("%d",score); } }
4.蛇吃到食物時(shí)產(chǎn)生的變長(zhǎng)效果snake_link()函數(shù)
蛇的變長(zhǎng),當(dāng)蛇吃到食物的時(shí)候,此時(shí)我們將食物的坐標(biāo)變成蛇頭,然后進(jìn)行重新的打印蛇,即可以有蛇變成的效果產(chǎn)生,實(shí)質(zhì)為對(duì)循環(huán)鏈表進(jìn)行元素的插入。
即通過(guò)這樣將食物的坐標(biāo)插進(jìn)去循環(huán)鏈表,達(dá)到蛇變成的效果
代碼如下
struct snake *snake_link(struct snake *p) //蛇的連接 { struct snake *q; q = (struct snake *)malloc(sizeof(struct snake)); //即主要是實(shí)現(xiàn)了對(duì)循環(huán)鏈表的插入元素,再 q->x = food_xy[0]; //進(jìn)行打印蛇,即可有吃到食物蛇變長(zhǎng)的結(jié)果 q->y = food_xy[1]; q->pre = p->pre; p->pre->next = q; p->pre = q; q->next = p; return p; }
5.判斷蛇的死亡,分別為撞墻hit_wall()和自殺suicide()
撞墻,則只需判斷蛇頭的單一坐標(biāo)x軸或者y軸是否與墻壁的坐標(biāo)是否相等,若相等則說(shuō)明蛇撞墻了
代碼如下
void hit_wall(int n) //判斷蛇是否撞墻,即對(duì)蛇的單一坐標(biāo)x或者y進(jìn)行判斷,若等于墻壁的值,即游戲結(jié)束 { if(ch == 'W'|| ch == 'S' ) if(n == 1 || n == 25) //墻壁的坐標(biāo)值 { 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); } }
自殺suicide()即蛇頭是否有撞到了蛇身,做法是把蛇頭的坐標(biāo)拿出來(lái),與蛇身的坐標(biāo)進(jìn)行對(duì)比如果相等,說(shuō)明蛇頭撞到了蛇身,本質(zhì)上是循環(huán)鏈表的值進(jìn)行匹配,遍歷
代碼如下
void suicide(struct snake *p, int x, int y) //自殺,即撞到自己本身的時(shí)候游戲結(jié)束 { struct snake *q; //把蛇頭坐標(biāo)傳遞進(jìn)來(lái),然后與其自己身體坐標(biāo)做對(duì)比若有相等則表明,蛇頭撞到了蛇身 q = p; while(q != p->next) //即對(duì)循環(huán)鏈表的遍歷匹配 { if(p->x == x && p->y == y) { gotoxy(0,26); printf("游戲結(jié)束!"); printf("你的得分:%d",score); exit(0); } else p = p->next; } }
到此蛇的基本功能已經(jīng)講完,以下是全部代碼。
全部代碼如下
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <conio.h> #include <time.h> #define SNAKE_SPEED 200 //蛇移動(dòng)的速度 int score = 0; //成績(jī)得分 int flag = 0; //用于判斷地圖上是否存在食物,0為不存在食物 int food_xy[2]; //定位食物的位置 char ch; //用來(lái)決定蛇的移動(dòng)方向 struct snake //定義一條循環(huán)鏈表的蛇 { int x; int y; struct snake *next; struct snake *pre; }; void HideCursor()//把蛇移動(dòng)的時(shí)候產(chǎn)生的光標(biāo)進(jìn)行隱藏,隱藏光標(biāo)函數(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) //定位光標(biāo)函數(shù),用來(lái)實(shí)現(xiàn)蛇的移動(dòng),和食物的出現(xiàn)(傳送x,y可以將光標(biāo)定位到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() //給蛇進(jìn)行初始化,構(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()來(lái)對(duì)蛇進(jìn)行打印,只需遍歷一次循環(huán)鏈表即可將坐標(biāo)可視化為一條蛇 { struct snake *q; q = p; while(q != p->next) //循環(huán)鏈表的遍歷 { gotoxy(p->x,p->y); //根據(jù)坐標(biāo)和定位光標(biāo)函數(shù)來(lái)打@,實(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的值來(lái)判斷地圖上是否有食物 { srand( (unsigned)time( NULL ) ); for( i = 0; i < 2; i++ ) //對(duì)food_(x,y)來(lái)隨機(jī)賦值 { food_xy[i] = rand()%24+2; while(food_xy[0] == 1 || food_xy[0] == 25) //這兩個(gè)while為了防止食物的坐標(biāo)與地圖的邊緣重疊 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)); //即主要是實(shí)現(xiàn)了對(duì)循環(huán)鏈表的插入元素,再進(jìn)行打印蛇,即可有吃到食物蛇變長(zhǎng)的結(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) //蛇吃到食物,即主要是對(duì)蛇頭的x,y坐標(biāo)和food_xy的坐標(biāo)進(jìn)行匹配對(duì)比,若相同即調(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) //判斷蛇是否撞墻,即對(duì)蛇的單一坐標(biāo)x或者y進(jìn)行判斷,若等于墻壁的值,即游戲結(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) //自殺,即撞到自己本身的時(shí)候游戲結(jié)束 { struct snake *q; //把蛇頭坐標(biāo)傳遞進(jìn)來(lái),然后與其自己身體坐標(biāo)做對(duì)比若有相等則表明,蛇頭撞到了蛇身 q = p; while(q != p->next) //即對(duì)循環(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) //向上移動(dòng) { int x; int y; x = p->pre->x; //將蛇頭坐標(biāo)賦值給x,y y = p->pre->y; while(p) //對(duì)循環(huán)鏈表的遍歷,即蛇的遍歷 { Sleep(SNAKE_SPEED); //蛇移動(dòng)的速度 y--; //向上移動(dòng)則只需將縱坐標(biāo)進(jìn)行減,就可以實(shí)現(xiàn)蛇向上移動(dòng)的效果 gotoxy(p->x,p->y); //定位到蛇尾,輸出“ ”即蛇尾消失 printf(" "); gotoxy(x, y); //定位到蛇頭輸出,"@",結(jié)合上面的蛇尾消失又進(jìn)行蛇頭打印,產(chǎn)生蛇移動(dòng)的效果 printf("@"); suicide(p,x,y); //判斷蛇頭是否撞到蛇身 p = p->next; //將蛇頭的坐標(biāo)變?yōu)橄乱粋€(gè) p->pre->x = x; //此時(shí)將前一個(gè)蛇頭變成蛇尾,通過(guò)不斷的遍歷產(chǎn)生不斷移動(dòng)的效果 p->pre->y = y; food(); //產(chǎn)生食物 eat_food(p,x,y); //判斷是否吃到食物 hit_wall(y); //判斷是否撞墻 if(kbhit()) break; //判斷是否有按鍵輸入,有就進(jìn)行蛇移動(dòng)方向的改變 } return p; } struct snake *left(struct snake *p) //向左移動(dòng) { 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) //向下移動(dòng) { 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) //向右移動(dòng) { 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) //蛇的移動(dòng)函數(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); //移動(dòng)蛇 return 0; }
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,分享給大家:
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
一起來(lái)看看C語(yǔ)言的預(yù)處理注意點(diǎn)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的預(yù)處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03關(guān)于C++中菱形繼承和虛繼承的問(wèn)題總結(jié)
C++的三大特性為:封裝,繼承,多態(tài)。但是在繼承中,存在一些使用方面的問(wèn)題需要注意,下面這篇文章主要給大家總結(jié)介紹了關(guān)于C++中菱形繼承和虛繼承的問(wèn)題,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-08-08C++實(shí)現(xiàn)LeetCode(208.實(shí)現(xiàn)字典樹(shù)(前綴樹(shù)))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(208.實(shí)現(xiàn)字典樹(shù)(前綴樹(shù))),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08C++中的STL中map用法詳解(零基礎(chǔ)入門(mén))
map在編程中是經(jīng)常使用的一個(gè)容器,本文來(lái)講解一下STL中的map,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08基于C++ bitset常用函數(shù)及運(yùn)算符(詳解)
下面小編就為大家?guī)?lái)一篇基于C++ bitset常用函數(shù)及運(yùn)算符(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11C/C++?Qt?選擇夾TabWidget組件實(shí)現(xiàn)導(dǎo)航欄切換
Tab切換在很多地方都可以使用的到,本文就使用TabWidget組件來(lái)實(shí)現(xiàn)一下,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11