C語言代碼鏈表實現(xiàn)貪吃蛇游戲
本文實例為大家分享了C語言鏈表實現(xiàn)貪吃蛇游戲的具體代碼,供大家參考,具體內(nèi)容如下
貪吃蛇設(shè)計思路:
屏幕坐標(biāo):
拓展功能:
1.F1,F(xiàn)2控制加速減速 空格暫停游戲 Esc退出
2.加速每個食物得分更高
先打印出游戲界面,還有初始化蛇,蛇的節(jié)點用字符串★表示,游戲背景用■表示,因為這些字符串占兩個字節(jié)的寬度,所以每次x,y坐標(biāo)的對應(yīng)關(guān)系是x=y*2。在相應(yīng)位置打印出蛇,初始化蛇為五個節(jié)點
初始化蛇頭的移動方向為右,根據(jù)按鍵來確定蛇的移動狀態(tài),要是吃到食物,就讓食物為蛇頭,然后隨機生成食物。
重點模塊:
蛇移動的實現(xiàn):
定義一個結(jié)構(gòu)體,里面放節(jié)點坐標(biāo),和next指針。
蛇每次移動是通過用戶按鍵方向來確定下一個蛇頭節(jié)點的x,y坐標(biāo),新建一個節(jié)點賦給下一個坐標(biāo),在這個坐標(biāo)打出蛇的圖標(biāo),找到尾節(jié)點,將尾節(jié)點打印成背景圖標(biāo),再將節(jié)點釋放,這樣蛇就動了一下,以此重復(fù),蛇就可以了動態(tài)移動。
食物的實現(xiàn):
定義一個食物節(jié)點,也是一個類似于蛇的結(jié)構(gòu)體指針,通過隨機數(shù)生成坐標(biāo),注意不能在墻上和蛇身上。
用戶按鍵的檢測:可以使用wasd的字符來確定方向,但這里我們還需要使用空格,ESC鍵,上下左右鍵,所以直接一點,通過GetAsyncKeyState( )函數(shù)檢測用戶輸入的按鍵,需要引用頭文件conio.h,_getch()函數(shù)用來檢測當(dāng)前是否有按鍵輸入,有的話返回非0的數(shù)。
蛇的變速:還是通過GetAsyncKeyState( )函數(shù)檢測F1,F(xiàn)2,鍵來確定蛇移動一次Sleep()函數(shù)中的毫秒數(shù),這樣就實現(xiàn)了蛇的加速減速。而且蛇每移動一次,不必使用system(“cls")來清屏,通過在循環(huán)中snakemove()執(zhí)行一次,Sleep()函數(shù)執(zhí)行一次,就實現(xiàn)了動態(tài)移動。
實現(xiàn)效果:
完整代碼:
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<time.h> #include<windows.h> #include<stdlib.h> #include<conio.h> //接收鍵盤輸入輸出 #define U 1 #define D 2 #define L 3 #define R 4 //蛇的狀態(tài),U:上 ;D:下;L:左 R:右 /*******定 義 全 局 變 量 *******/ typedef struct snake //蛇身的一個節(jié)點 { int x; int y; struct snake *next; }snake; int score=0,add=10; //總得分與每次吃食物得分 int status,sleeptime=200; //蛇前進狀態(tài),每次運行的時間間隔 snake *head, *food; //蛇頭指針,食物指針 snake *q; //遍歷蛇的時候用到的指針 int endgamestatus=0; //游戲結(jié)束的情況,1:撞到墻;2:咬到自己;3:主動退出游戲。 HANDLE hOut; //控制臺句柄 /*******函 數(shù) 聲 明 *******/ void gotoxy(int x,int y); //設(shè)置光標(biāo)位置 int color(int c); //更改文字顏色 void welcometogame(); //開始界面 void createMap(); //繪制地圖 void scoreandtips(); //游戲界面右側(cè)的得分和小提示 void initsnake(); //初始化蛇身,畫蛇身 void createfood(); //創(chuàng)建并隨機出現(xiàn)食物 int biteself(); //判斷是否咬到了自己 void cantcrosswall(); //設(shè)置蛇撞墻的情況 void speedup(); //加速 void speeddown(); //減速 void snakemove(); //控制蛇前進方向 void keyboardControl(); //控制鍵盤按鍵 void Lostdraw(); //游戲結(jié)束界面 void endgame(); //游戲結(jié)束 void choose(); //游戲失敗之后的選擇 void explation(); //游戲說明 /** * 設(shè)置光標(biāo)位置 */ void gotoxy(int x,int y) { COORD c; c.X=x; c.Y=y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c); } /** * 文字顏色函數(shù) */ int color(int c) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //更改文字顏色 return 0; } //開始界面 void welcometogame() { int n; gotoxy(43,10); color(11); printf("貪 吃 蛇 大 作 戰(zhàn)"); color(12); gotoxy(25, 22); printf("1.開始游戲"); gotoxy(45, 22); printf("2.游戲說明"); gotoxy(65, 22); printf("3.退出游戲"); gotoxy(40,27); color(3); printf("請選擇 1 2 3:"); color(14); scanf("%d", &n); //輸入選項 switch (n) { case 1: system("cls"); createMap(); //創(chuàng)建地圖 initsnake(); //初始化蛇身 createfood(); //創(chuàng)建食物 keyboardControl(); //按鍵控制 break; case 2: explation(); //游戲說明函數(shù) break; case 3: exit(0); //退出游戲 break; default: color(12); gotoxy(40,28); printf("請輸入1—3之間的數(shù)!"); _getch(); //輸入任意鍵 system("cls"); //清屏 welcometogame(); } } //創(chuàng)建地圖 void createMap() { int i,j; for(i=0;i<58;i+=2) //打印上下邊框 { gotoxy(i,0); color(5); printf("□"); gotoxy(i,26); printf("□"); } for(i=1;i<26;i++) //打印左右邊框 { gotoxy(0,i); printf("□"); gotoxy(56,i); printf("□"); } for(i = 2;i<56;i+=2) //打印中間網(wǎng)格 { for(j = 1;j<26;j++) { gotoxy(i,j); color(3); printf("■"); } } } // 游戲界面右側(cè)的得分和小提示 void scoreandtips() { gotoxy(64,8); color(14); printf("得分:%d ",score); gotoxy(64,14); printf("每個食物得分:%d分",add); gotoxy(64,16); printf("不能穿墻,不能咬到自己"); gotoxy(64,18); printf("用↑ ↓ ← →分別控制蛇的移動"); gotoxy(64,20); printf("F1 為加速,F(xiàn)2 為減速"); gotoxy(64,22); printf("space:暫停游戲"); gotoxy(64,24); printf("ESC :退出游戲"); } //初始化蛇身,畫蛇身 void initsnake() { snake *tail; int i; tail=(snake*)malloc(sizeof(snake));//從蛇尾開始,頭插法,以x,y設(shè)定開始的位置 tail->x=24; //蛇的初始位置(24,5) tail->y=5; tail->next=NULL; for(i=1;i<=4;i++) //設(shè)置蛇身,長度為5 { head=(snake*)malloc(sizeof(snake)); //初始化蛇頭 head->next=tail; //蛇頭的下一位為蛇尾 head->x=24+2*i; //設(shè)置蛇頭位置 head->y=5; tail=head; //蛇頭變成蛇尾,然后重復(fù)循環(huán) } while(tail!=NULL) //從頭到尾,輸出蛇身 { gotoxy(tail->x,tail->y); color(14); printf("★"); //輸出蛇身,蛇身使用★組成 tail=tail->next; //蛇頭輸出完畢,輸出蛇頭的下一位,一直輸出到蛇尾 } } /** * 隨機出現(xiàn)食物 */ void createfood() { snake *food_1; srand((unsigned)time(NULL)); //初始化隨機數(shù) food_1=(snake*)malloc(sizeof(snake)); //初始化food_1 while((food_1->x%2)!=0) //保證其為偶數(shù),使得食物能與蛇頭對其,然后食物會出現(xiàn)在網(wǎng)格線上 { food_1->x=rand()%52+2; //食物隨機出現(xiàn) } food_1->y=rand()%24+1; q=head; while(q->next==NULL) { if(q->x==food_1->x && q->y==food_1->y) //判斷蛇身是否與食物重合 { free(food_1); //如果蛇身和食物重合,那么釋放食物指針 createfood(); //重新創(chuàng)建食物 } q=q->next; } gotoxy(food_1->x,food_1->y); food=food_1; color(12); printf("●"); //輸出食物 } /** * 判斷是否咬到了自己 */ int biteself() { snake *self; //定義self為蛇身上的一個節(jié)點 self=head->next; //self是蛇頭之外的蛇身上的節(jié)點 while(self!=NULL) { if(self->x==head->x && self->y==head->y) //如果self和蛇身上的節(jié)點重合 { return 1; //返回1 } self=self->next; } return 0; } /** * 設(shè)置蛇撞墻的情況 */ void cantcrosswall() { if(head->x==0 || head->x==56 ||head->y==0 || head->y==26) //如果蛇頭碰到了墻壁 { endgamestatus=1; //返回第一種情況 endgame(); //出現(xiàn)游戲結(jié)束界面 } } /** * 加速,蛇吃到食物會自動提速,并且按F1會加速 */ void speedup() { if(sleeptime>=50) { sleeptime=sleeptime-10; add=add+2; } } /** * 加速,按F2會減速 */ void speeddown() { if(sleeptime<350) //如果時間間隔小于350 { sleeptime=sleeptime+30; //時間間隔加上30 add=add-2; //每吃一次食物的得分減2 } } /** * 控制方向 問題:為什么要設(shè)置status,而不使用前兩章中接收鍵盤按鍵的方法 */ void snakemove() //蛇前進,上U,下D,左L,右R { snake * nexthead; cantcrosswall(); nexthead=(snake*)malloc(sizeof(snake)); //為下一步開辟空間 if(status==U) { nexthead->x=head->x; //向上前進時,x坐標(biāo)不動,y坐標(biāo)-1 nexthead->y=head->y-1; nexthead->next=head; head=nexthead; q=head; //指針q指向蛇頭 if(nexthead->x==food->x && nexthead->y==food->y) //如果下一個有食物 下一個位置的坐標(biāo)和食物的坐標(biāo)相同 { while(q!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); //原來食物的位置,從●換成★ q=q->next; //指針q指向的蛇身的下一位也執(zhí)行循環(huán)里的操作 } score=score+add; //吃了一個食物,在總分上加上食物的分 speedup(); createfood(); //創(chuàng)建食物 } else { while(q->next->next!=NULL) //如果沒遇到食物 { gotoxy(q->x,q->y); color(14); printf("★"); //蛇正常往前走,輸出當(dāng)前位置的蛇身 q=q->next; //繼續(xù)輸出整個蛇身 } gotoxy(q->next->x,q->next->y); //經(jīng)過上面的循環(huán),q指向蛇尾,蛇尾的下一位,就是蛇走過去的位置 color(3); printf("■"); free(q->next); //進行輸出■之后,釋放指向下一位的指針 q->next=NULL; //指針下一位指向空 } } if(status==D) { nexthead->x=head->x; //向下前進時,x坐標(biāo)不動,y坐標(biāo)+1 nexthead->y=head->y+1; nexthead->next=head; head=nexthead; q=head; if(nexthead->x==food->x && nexthead->y==food->y) //有食物 { while(q!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } score=score+add; speedup(); createfood(); } else //沒有食物 { while(q->next->next!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } gotoxy(q->next->x,q->next->y); color(3); printf("■"); free(q->next); q->next=NULL; } } if(status==L) { nexthead->x=head->x-2; //向左前進時,x坐標(biāo)向左移動-2,y坐標(biāo)不動 nexthead->y=head->y; nexthead->next=head; head=nexthead; q=head; if(nexthead->x==food->x && nexthead->y==food->y)//有食物 { while(q!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } score=score+add; speedup(); createfood(); } else //沒有食物 { while(q->next->next!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } gotoxy(q->next->x,q->next->y); color(3); printf("■"); free(q->next); q->next=NULL; } } if(status==R) { nexthead->x=head->x+2; //向右前進時,x坐標(biāo)向右移動+2,y坐標(biāo)不動 nexthead->y=head->y; nexthead->next=head; head=nexthead; q=head; if(nexthead->x==food->x && nexthead->y==food->y)//有食物 { while(q!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } score=score+add; speedup(); createfood(); } else //沒有食物 { while(q->next->next!=NULL) { gotoxy(q->x,q->y); color(14); printf("★"); q=q->next; } gotoxy(q->next->x,q->next->y); color(3); printf("■"); free(q->next); q->next=NULL; } } if(biteself()==1) //判斷是否會咬到自己 { endgamestatus=2; endgame(); } } /** * 控制鍵盤按鍵 */ void keyboardControl() { status=R; //初始蛇向右移動 while(1) { scoreandtips(); if(GetAsyncKeyState(VK_UP) && status!=D) //GetAsyncKeyState函數(shù)用來判斷函數(shù)調(diào)用時指定虛擬鍵的狀態(tài) { status=U; //如果蛇不是向下前進的時候,按上鍵,執(zhí)行向上前進操作 } else if(GetAsyncKeyState(VK_DOWN) && status!=U) //如果蛇不是向上前進的時候,按下鍵,執(zhí)行向下前進操作 { status=D; } else if(GetAsyncKeyState(VK_LEFT)&& status!=R) //如果蛇不是向右前進的時候,按左鍵,執(zhí)行向左前進 { status=L; } else if(GetAsyncKeyState(VK_RIGHT)&& status!=L) //如果蛇不是向左前進的時候,按右鍵,執(zhí)行向右前進 { status=R; } if(GetAsyncKeyState(VK_SPACE)) //按暫停鍵,執(zhí)行pause暫停函數(shù) { while(1) { Sleep(300); //sleep()函數(shù),頭文件#include <unistd.h> 另進程暫停,知道達(dá)到里面設(shè)定的參數(shù)的時間。 if(GetAsyncKeyState(VK_SPACE)) //按空格鍵暫停 { break; } } } else if(GetAsyncKeyState(VK_ESCAPE)) { endgamestatus=3; //按esc鍵,直接到結(jié)束界面 break; } else if(GetAsyncKeyState(VK_F1)) //按F1鍵,加速 { speedup(); } else if(GetAsyncKeyState(VK_F2)) //按F2鍵,減速 { speeddown(); } Sleep(sleeptime); snakemove(); } } /* * 游戲說明 */ void explation() { //int i,j = 1; system("cls"); // color(13); // gotoxy(44,3); // printf("游戲說明"); // color(2); // for (i = 6; i <= 22; i++) //輸出上下邊框=== //{ // for (j = 20; j <= 75; j++) //輸出左右邊框|| // { // gotoxy(j, i); // if (i == 6 || i == 22) printf("="); // else if (j == 20 || j == 75) printf("||"); // } //} color(3); gotoxy(30,8); printf("1. 不能穿墻,不能咬到自己"); color(10); gotoxy(30,11); printf("2. 用↑.↓.←.→分別控制蛇的移動"); color(14); gotoxy(30,14); printf("3. F1 為加速,F(xiàn)2 為減速"); color(11); gotoxy(30,17); printf("4. 按空格鍵暫停游戲,再按空格鍵繼續(xù)"); color(4); gotoxy(30,20); printf("5. ESC :退出游戲.space:暫停游戲"); _getch(); //按任意鍵返回主界面 system("cls"); welcometogame(); } /** * 結(jié)束游戲 */ void endgame() { system("cls"); if(endgamestatus==1) { //Lostdraw(); gotoxy(43,9); color(12); printf("GAME OVER !"); } else if(endgamestatus==2) { //Lostdraw(); gotoxy(43,9); color(12); printf("GAME OVER !"); } else if(endgamestatus==3) { //Lostdraw(); gotoxy(40,9); color(12); printf("已結(jié)束游戲。"); } gotoxy(43,12); color(13); printf("你的得分是 %d",score); choose(); } /** * 邊框下面的分支選項 */ void choose() { int n; gotoxy(25,23); color(12); printf("Continue ------ 1"); gotoxy(52,23); printf("Exit ------ 2"); gotoxy(45,25); color(11); printf("選擇: "); scanf("%d", &n); switch (n) { case 1: system("cls"); //清屏 score=0; //分?jǐn)?shù)歸零 sleeptime=200; //設(shè)定初始速度 add = 10; //使add設(shè)定為初值,吃一個食物得分10,然后累加 welcometogame(); break; case 2: exit(0); //退出游戲 break; default: gotoxy(35,27); color(12); printf(" 輸入有誤 重新輸入 !"); system("pause >nul"); endgame(); choose(); break; } } /** * 失敗界面 */ void Lostdraw() { system("cls"); int i; gotoxy(45,2); color(6); printf("\\\\\\|///"); gotoxy(43,3); printf("\\\\"); gotoxy(47,3); color(15); printf(".-.-"); gotoxy(54,3); color(6); printf("http://"); gotoxy(44,4); color(14); printf("("); gotoxy(47,4); color(15); printf(".@.@"); gotoxy(54,4); color(14); printf(")"); gotoxy(17,5); color(11); printf("+------------------------"); gotoxy(35,5); color(14); printf("oOOo"); gotoxy(39,5); color(11); printf("----------"); gotoxy(48,5); color(14); printf("(_)"); gotoxy(51,5); color(11); printf("----------"); gotoxy(61,5); color(14); printf("oOOo"); gotoxy(65,5); color(11); printf("-----------------+"); for(i = 6;i<=19;i++) //豎邊框 { gotoxy(17,i); printf("|"); gotoxy(82,i); printf("|"); } gotoxy(17,20); printf("+---------------------------------"); gotoxy(52,20); color(14); printf("☆☆☆〃"); gotoxy(60,20); color(11); printf("----------------------+"); } /** * 主函數(shù) */ int main() { system("mode con cols=100 lines=30"); //設(shè)置控制臺的寬高 //printsnake(); welcometogame(); keyboardControl(); endgame(); return 0; }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Qt動態(tài)庫調(diào)用宿主進程中的對象方法純虛函數(shù)使用
這篇文章主要為大家介紹了Qt動態(tài)庫調(diào)用宿主進程中的對象方法純虛函數(shù)使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-08-08C++實現(xiàn)通訊錄系統(tǒng)項目實戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了C++實現(xiàn)通訊錄系統(tǒng)項目實戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06C語言文件操作 fopen, fclose, mkdir詳解
本文給大家詳細(xì)介紹了下C語言的文件操作函數(shù)fopen, fclose, mkdir的用法及示例,非常的簡單實用,有需要的小伙伴可以參考下。2016-03-03基于WTL 雙緩沖(double buffer)繪圖的分析詳解
本篇文章是對WTL下使用雙緩沖(double buffer)繪圖進行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05