這篇文章給大家分享的是有關(guān)C語言如何實現(xiàn)單鏈表控制臺貪吃蛇小游戲的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
創(chuàng)新互聯(lián)公司服務(wù)項目包括呼中網(wǎng)站建設(shè)、呼中網(wǎng)站制作、呼中網(wǎng)頁制作以及呼中網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,呼中網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到呼中省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
C語言實現(xiàn)單鏈表控制臺貪吃蛇小游戲,供大家參考。
編譯環(huán)境:vs2019
需求:
統(tǒng)計游戲開始后的時間,控制貪吃蛇;吃到食物蛇身加長,得分加一;碰墻或蛇頭碰到身體減一條生命;生命消耗完則結(jié)束游戲。
思路:
使用wasd鍵控制蛇的移動方向,蛇頭碰到食物得分加一,并在地圖上隨機產(chǎn)生一個食物,累加得分,碰墻或碰自己減一條生命,并初始化整條蛇,生命值為0時結(jié)束游戲。
做法:
使用單鏈表控制貪吃蛇移動的核心思想就是:鏈表存儲貪吃蛇所有坐標(biāo),每次循環(huán)貪吃蛇不斷向一個方向插入一個新的結(jié)點作為新的蛇頭,按下按鍵控制新蛇頭產(chǎn)生的位置,然后從新蛇頭處遍歷鏈表輸出蛇身到上一個蛇尾,清除上一個蛇尾的痕跡,并釋放相關(guān)結(jié)點。
每次向鏈表插入新節(jié)點后,判斷新節(jié)點的坐標(biāo)是否和食物的坐標(biāo)重合,如果重合本輪循環(huán)不釋放清除蛇尾結(jié)點,反之釋放清除上一個蛇尾的結(jié)點。
另外,在寫蛇生命相關(guān)代碼的時候,還需要注意一下哪些值應(yīng)該初始化,哪些值不應(yīng)該初始化。
只要明白了貪吃蛇運動的核心思想,整個程序其實就不難寫出來。
難點:
wsad控制貪吃蛇上下左右移動,并清除蛇尾。
說明:
使用單鏈表實現(xiàn)貪吃蛇的核心思想是我一開始沒有想到的,部分相關(guān)代碼我學(xué)習(xí)并借鑒了一些網(wǎng)絡(luò)上搜索到的代碼,如果有違反了相關(guān)版權(quán)協(xié)議,請告知我修改相關(guān)代碼。
注意:
由于編譯器原因程序中_kbhit()和_getch()函數(shù)可能在其他編譯器上編譯會出現(xiàn)錯誤,解決辦法是去掉函數(shù)前面的“_”。
運行效果:
代碼實現(xiàn):
#include#include #include #include #include void HideCursor(); //光標(biāo)隱藏 void gotoxy(int x, int y); //光標(biāo)定位 typedef struct snake { int x; int y; struct snake* next; }snake; #define WIDTH 100 //控制臺窗口寬度 #define HEIGHT 30 //控制臺窗口高度 #define SNAKEN 4 //貪吃蛇初始長度 #define LIFE 3 //初始生命次數(shù) #define SPEED 200 //游戲速度、循環(huán)休眠時間 #define U 1 //使用宏代替需要數(shù)字代替的蛇的行動方向 #define D 2 //宏名含義是各方向英文單詞首字母 #define L 3 //蛇的狀態(tài),U:上 ;D:下;L:左 R:右 #define R 4 void dtxxcsh() //輸出地圖 { for (int i = 1; i < WIDTH-1; i++) //輸出上下面墻 { gotoxy(i, 26); printf("-"); gotoxy(i, 0); printf("-"); } for (int i = 0; i < HEIGHT-3; i++) //輸出左右兩面墻 { gotoxy(0, i); printf("|"); gotoxy(99, i); printf("|"); } gotoxy(24, 28); printf("得分: 0 生命: %d 時間: 0 ",LIFE); //xy 30,28可用得分?jǐn)?shù)值 14個空格 } int foodx, foody; //食物位置坐標(biāo) void sjcsswhs() //隨機產(chǎn)生一個食物 { srand(time(NULL)); foodx = rand() % (WIDTH - 4) + 2; //使用宏運算隨機數(shù)最大值需要加括號 while (foodx % 2) //如果食物的x坐標(biāo)不是偶數(shù),再獲取一個x坐標(biāo) { foodx = rand() % (WIDTH - 4) + 2; //寬度 } foody = rand() % (HEIGHT - 7) + 3; //高度 gotoxy(foodx, foody); printf("★"); } snake* head; //蛇頭指針 void cshs() //初始化蛇的位置 { snake *tail; //蛇尾指針 int i; tail = (snake*)malloc(sizeof(snake)); tail->next = NULL; tail->x = HEIGHT-6; tail->y = 8; //貪吃蛇初始長度5 SNAKEN for (i = 1; i <= SNAKEN; i++) //在蛇尾處創(chuàng)建鏈表 { head = (snake*)malloc(sizeof(snake)); head->next = tail; head->x = 24 + i * 2; //head->x這個數(shù)必須為偶數(shù),和食物坐標(biāo)偶數(shù)對應(yīng) head->y = 8; tail = head; //此時蛇尾指針指向蛇頭 } while (tail) { gotoxy(tail->x, tail->y); printf("■"); tail = tail->next; } } int status = R; //蛇前進狀態(tài) snake* p = NULL; //工作指針 snake* nexthead; //下一個蛇頭 int score = 0; //得分 void snakemove() //蛇前進,上U,下D,左L,右R { nexthead = (snake*)malloc(sizeof(snake)); if (status == U) { nexthead->y = head->y - 1; //確定新蛇頭的下一個坐標(biāo) x,y nexthead->x = head->x; } if (status == D) //下 { nexthead->y = head->y + 1; nexthead->x = head->x; } if (status == L) //左 { nexthead->x = head->x - 2; nexthead->y = head->y; } if (status == R) //右 { nexthead->x = head->x + 2; nexthead->y = head->y; } nexthead->next = head; head = nexthead; p = head; if (p->x == foodx && p->y == foody) //判斷蛇頭的位置是否和食物的位置重合 { while (p) //輸出尾結(jié)點 { gotoxy(p->x, p->y); if (p == head) printf("●"); else printf("■"); p = p->next; //因為每次運動都是新創(chuàng)建一個頭結(jié)點再刪除一個尾結(jié)點, } //所以要增加一節(jié)身體,只需要這次循環(huán)不釋放尾結(jié)點,并輸出一次尾結(jié)點就好了 //sjcsswhs(); //碰到食物則再產(chǎn)生一個食物 score++; gotoxy(32, 28); printf("%d", score); } else { while (p->next->next) //不輸出尾結(jié)點 { gotoxy(p->x, p->y); if (p == head) printf("●"); else printf("■"); p = p->next; } gotoxy(p->next->x, p->next->y); printf(" "); free(p->next); p->next = NULL; } p = head; while (p) //如果食物的坐標(biāo)刷新到了蛇身上則再產(chǎn)生一個食物 * { if (p->x == foodx && p->y == foody) sjcsswhs(); p = p->next; } } void czfxhs() //操作方向函數(shù),接收從鍵盤輸入的按鍵,控制貪吃蛇行進方向 { char ch = _getch(); switch (ch) { case 'w': if(status != D) status = U; break; case 's': if (status != U) status = D; break; case 'a': if (status != R) status = L; break; case 'd': if (status != L) status = R; break; case ' ': _getch(); break; //空格暫停 } } int yxjstjjsmz_1() //生命掉落條件1咬自己 { snake* self = head->next; //self為蛇身上的一個結(jié)點 while (self) { if (self->x == head->x && self->y == head->y) //head和self的成員作比較,蛇頭一直存在,這里遍歷的是蛇身 { return 1; } self = self->next; } return 0; } int yxjstjjsmz_2() //生命掉落條件2碰墻 { if (head->x <= 1 || head->x >= 98 || head->y <= 0 || head->y >= 26) return 1; return 0; } int i = LIFE - 1; //變量存儲生命次數(shù) void qcsytmslbhs() //清除并釋放上一條蛇留下來的痕跡,更新生命信息 { p = head; int _x_ = p->x; //用于保存死掉的蛇的蛇頭處的位置,用于輸出被蛇頭頂?shù)舻膲Ρ? int _y_ = p->y; while (head) { gotoxy(head->x, head->y); printf(" "); head = head->next; free(p); p = head; } gotoxy(52, 28); //更新生命信息 printf("%d", i); if (_y_ == 0 || _y_ == HEIGHT - 4) //用于在蛇死掉后,蛇頭的位置輸出被清除蛇頭頂替掉的墻壁 { gotoxy(_x_, _y_); printf("--"); } else if (_x_ == WIDTH - 2) { gotoxy(_x_+1, _y_); printf("|"); } else if(_x_ == 0) { gotoxy(_x_, _y_); printf("|"); } } void sbjsjmhs() //失敗結(jié)束界面 { p = head; //釋放內(nèi)存 while (head) { head = head->next; free(p); p = head; } system("cls"); gotoxy(45, 12); printf("游戲結(jié)束!"); gotoxy(44, 14); printf("最終得分:%d", score); gotoxy(0,28); } int updatetime() //獲取一次電腦現(xiàn)在的時間 { int now; SYSTEMTIME system_time; GetLocalTime(&system_time); now = system_time.wMinute * 60 + system_time.wSecond; return now; } int time_1 = updatetime(); //保存游戲剛開始的時間 void gametime() //寫在每次循環(huán)之內(nèi) { int time_2 = updatetime() - time_1; //更新游戲開始后時間,用現(xiàn)在的時間減去剛開始的時間 gotoxy(72, 28); printf("%d s", time_2); } int main()//主函數(shù) { system("mode con cols=100 lines=30"); //設(shè)置控制臺大小 system("title 貪吃蛇游戲"); //設(shè)置標(biāo)題 HideCursor(); //隱藏光標(biāo) sjcsswhs(); //初始化隨機產(chǎn)生一個食物 dtxxcsh(); //初始化地圖、信息 for (; i >= 0; i--) //生命 { cshs(); //初始化蛇的位置 status = R; //初始化運動方向 while (1) { snakemove(); //蛇行動動畫,方向被控制變量控制 if (_kbhit()) { czfxhs(); //接收鍵盤按鍵,控制控制變量 } if (yxjstjjsmz_1() || yxjstjjsmz_2())//兩個掉落生命的條件 break; gametime(); //更新游戲時間 Sleep(SPEED); } qcsytmslbhs(); //清除上一條蛇留下來的痕跡,更新生命信息 } sbjsjmhs(); //失敗結(jié)束界面 return 0; } void HideCursor() { CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); } void gotoxy(int x, int y) { COORD pos = { x,y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); }
不足之處:
因為這是我第一次使用鏈表做一個完整的小程序,所以對鏈表的運用還很稚嫩,在代碼規(guī)范和嚴(yán)謹(jǐn)性上面還有很多問題。
另外關(guān)于“食物如果刷新到蛇身上則再隨機產(chǎn)生一個食物”(172行)相關(guān)代碼,我不是很確定到底完不完善。
作為一名c語言新手,我對未知的知識始終抱有學(xué)習(xí)和謙卑的態(tài)度,如有貴人能夠?qū)ξ业某绦蛱岢鼋ㄗh,我將不勝感激。
感謝各位的閱讀!關(guān)于“C語言如何實現(xiàn)單鏈表控制臺貪吃蛇小游戲”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!