C語言貪吃蛇(詳解)——連結串列實現
貪吃蛇設計思路:
螢幕座標:
拓展功能:
1.F1,F2控制加速減速 空格暫停遊戲 Esc退出
2.加速每個食物得分更高
先打印出遊戲介面,還有初始化蛇,蛇的節點用字串★表示,遊戲背景用■表示,因為這些字串佔兩個位元組的寬度,所以每次x,y座標的對應關係是x=y*2。在相應位置打印出蛇,初始化蛇為五個節點
初始化蛇頭的移動方向為右,根據按鍵來確定蛇的移動狀態,要是吃到食物,就讓食物為蛇頭,然後隨機生成食物,
重點模組:
蛇移動的實現:
定義一個結構體,裡面放節點座標,和next指標。
蛇每次移動是通過使用者按鍵方向來確定下一個蛇頭節點的x,y座標,新建一個節點賦給下一個座標,在這個座標打出蛇的圖示,找到尾節點,將尾節點列印成背景圖示,再將節點釋放,這樣蛇就動了一下,以此重複,蛇就可以了動態移動。
食物的實現:
定義一個食物節點,也是一個類似於蛇的結構體指標,通過隨機數生成座標,注意不能在牆上和蛇身上。
使用者按鍵的檢測:可以使用wasd的字元來確定方向,但這裡我們還需要使用空格,ESC鍵,上下左右鍵,所以直接一點,通過GetAsyncKeyState( )函式檢測使用者輸入的按鍵,需要引用標頭檔案conio.h,_getch()函式用來檢測當前是否有按鍵輸入,有的話返回非0的數。
蛇的變速:還是通過GetAsyncKeyState( )函式檢測F1,F2,鍵來確定蛇移動一次Sleep()函式中的毫秒數,這樣就實現了蛇的加速減速。而且蛇每移動一次,不必使用system(“cls")來清屏,通過在迴圈中snakemove()執行一次,Sleep()函式執行一次,就實現了動態移動。
實現效果:
完整程式碼:
#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 //蛇的狀態,U:上 ;D:下;L:左 R:右
/*******定 義 全 局 變 量 *******/
typedef struct snake //蛇身的一個節點
{
int x;
int y;
struct snake *next;
}snake;
int score=0,add=10; //總得分與每次吃食物得分
int status,sleeptime=200; //蛇前進狀態,每次執行的時間間隔
snake *head, *food; //蛇頭指標,食物指標
snake *q; //遍歷蛇的時候用到的指標
int endgamestatus=0; //遊戲結束的情況,1:撞到牆;2:咬到自己;3:主動退出遊戲。
HANDLE hOut; //控制檯控制代碼
/*******函 數 聲 明 *******/
void gotoxy(int x,int y); //設定游標位置
int color(int c); //更改文字顏色
void welcometogame(); //開始介面
void createMap(); //繪製地圖
void scoreandtips(); //遊戲介面右側的得分和小提示
void initsnake(); //初始化蛇身,畫蛇身
void createfood(); //建立並隨機出現食物
int biteself(); //判斷是否咬到了自己
void cantcrosswall(); //設定蛇撞牆的情況
void speedup(); //加速
void speeddown(); //減速
void snakemove(); //控制蛇前進方向
void keyboardControl(); //控制鍵盤按鍵
void Lostdraw(); //遊戲結束介面
void endgame(); //遊戲結束
void choose(); //遊戲失敗之後的選擇
void explation(); //遊戲說明
/**
* 設定游標位置
*/
void gotoxy(int x,int y)
{
COORD c;
c.X=x;
c.Y=y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}
/**
* 文字顏色函式
*/
int color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //更改文字顏色
return 0;
}
//開始介面
void welcometogame()
{
int n;
gotoxy(43,10);
color(11);
printf("貪 吃 蛇 大 作 戰");
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(); //建立地圖
initsnake(); //初始化蛇身
createfood(); //建立食物
keyboardControl(); //按鍵控制
break;
case 2:
explation(); //遊戲說明函式
break;
case 3:
exit(0); //退出遊戲
break;
default:
color(12);
gotoxy(40,28);
printf("請輸入1—3之間的數!");
_getch(); //輸入任意鍵
system("cls"); //清屏
welcometogame();
}
}
//建立地圖
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) //列印中間網格
{
for(j = 1;j<26;j++)
{
gotoxy(i,j);
color(3);
printf("■");
}
}
}
// 遊戲介面右側的得分和小提示
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 為加速,F2 為減速");
gotoxy(64,22);
printf("space:暫停遊戲");
gotoxy(64,24);
printf("ESC :退出遊戲");
}
//初始化蛇身,畫蛇身
void initsnake()
{
snake *tail;
int i;
tail=(snake*)malloc(sizeof(snake));//從蛇尾開始,頭插法,以x,y設定開始的位置
tail->x=24; //蛇的初始位置(24,5)
tail->y=5;
tail->next=NULL;
for(i=1;i<=4;i++) //設定蛇身,長度為5
{
head=(snake*)malloc(sizeof(snake)); //初始化蛇頭
head->next=tail; //蛇頭的下一位為蛇尾
head->x=24+2*i; //設定蛇頭位置
head->y=5;
tail=head; //蛇頭變成蛇尾,然後重複迴圈
}
while(tail!=NULL) //從頭到尾,輸出蛇身
{
gotoxy(tail->x,tail->y);
color(14);
printf("★"); //輸出蛇身,蛇身使用★組成
tail=tail->next; //蛇頭輸出完畢,輸出蛇頭的下一位,一直輸出到蛇尾
}
}
/**
* 隨機出現食物
*/
void createfood()
{
snake *food_1;
srand((unsigned)time(NULL)); //初始化隨機數
food_1=(snake*)malloc(sizeof(snake)); //初始化food_1
while((food_1->x%2)!=0) //保證其為偶數,使得食物能與蛇頭對其,然後食物會出現在網格線上
{
food_1->x=rand()%52+2; //食物隨機出現
}
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(); //重新建立食物
}
q=q->next;
}
gotoxy(food_1->x,food_1->y);
food=food_1;
color(12);
printf("●"); //輸出食物
}
/**
* 判斷是否咬到了自己
*/
int biteself()
{
snake *self; //定義self為蛇身上的一個節點
self=head->next; //self是蛇頭之外的蛇身上的節點
while(self!=NULL)
{
if(self->x==head->x && self->y==head->y) //如果self和蛇身上的節點重合
{
return 1; //返回1
}
self=self->next;
}
return 0;
}
/**
* 設定蛇撞牆的情況
*/
void cantcrosswall()
{
if(head->x==0 || head->x==56 ||head->y==0 || head->y==26) //如果蛇頭碰到了牆壁
{
endgamestatus=1; //返回第一種情況
endgame(); //出現遊戲結束介面
}
}
/**
* 加速,蛇吃到食物會自動提速,並且按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
}
}
/**
* 控制方向 問題:為什麼要設定status,而不使用前兩章中接收鍵盤按鍵的方法
*/
void snakemove() //蛇前進,上U,下D,左L,右R
{
snake * nexthead;
cantcrosswall();
nexthead=(snake*)malloc(sizeof(snake)); //為下一步開闢空間
if(status==U)
{
nexthead->x=head->x; //向上前進時,x座標不動,y座標-1
nexthead->y=head->y-1;
nexthead->next=head;
head=nexthead;
q=head; //指標q指向蛇頭
if(nexthead->x==food->x && nexthead->y==food->y) //如果下一個有食物 下一個位置的座標和食物的座標相同
{
while(q!=NULL)
{
gotoxy(q->x,q->y);
color(14);
printf("★"); //原來食物的位置,從●換成★
q=q->next; //指標q指向的蛇身的下一位也執行迴圈裡的操作
}
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); //經過上面的迴圈,q指向蛇尾,蛇尾的下一位,就是蛇走過去的位置
color(3);
printf("■");
free(q->next); //進行輸出■之後,釋放指向下一位的指標
q->next=NULL; //指標下一位指向空
}
}
if(status==D)
{
nexthead->x=head->x; //向下前進時,x座標不動,y座標+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座標向左移動-2,y座標不動
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座標向右移動+2,y座標不動
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函式用來判斷函式呼叫時指定虛擬鍵的狀態
{
status=U; //如果蛇不是向下前進的時候,按上鍵,執行向上前進操作
}
else if(GetAsyncKeyState(VK_DOWN) && status!=U) //如果蛇不是向上前進的時候,按下鍵,執行向下前進操作
{
status=D;
}
else if(GetAsyncKeyState(VK_LEFT)&& status!=R) //如果蛇不是向右前進的時候,按左鍵,執行向左前進
{
status=L;
}
else if(GetAsyncKeyState(VK_RIGHT)&& status!=L) //如果蛇不是向左前進的時候,按右鍵,執行向右前進
{
status=R;
}
if(GetAsyncKeyState(VK_SPACE)) //按暫停鍵,執行pause暫停函式
{
while(1)
{
Sleep(300); //sleep()函式,標頭檔案#include <unistd.h> 另程序暫停,知道達到裡面設定的引數的時間。
if(GetAsyncKeyState(VK_SPACE)) //按空格鍵暫停
{
break;
}
}
}
else if(GetAsyncKeyState(VK_ESCAPE))
{
endgamestatus=3; //按esc鍵,直接到結束介面
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 為加速,F2 為減速");
color(11);
gotoxy(30,17);
printf("4. 按空格鍵暫停遊戲,再按空格鍵繼續");
color(4);
gotoxy(30,20);
printf("5. ESC :退出遊戲.space:暫停遊戲");
_getch(); //按任意鍵返回主介面
system("cls");
welcometogame();
}
/**
* 結束遊戲
*/
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("已結束遊戲。");
}
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; //分數歸零
sleeptime=200; //設定初始速度
add = 10; //使add設定為初值,吃一個食物得分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("//");
gotoxy(44,4);
color(14);
printf("(");
gotoxy(47,4);
color(15);
printf(" [email protected]@");
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("----------------------+");
}
/**
* 主函式
*/
int main()
{
system("mode con cols=100 lines=30"); //設定控制檯的寬高
//printsnake();
welcometogame();
keyboardControl();
endgame();
return 0;
}
相關推薦
C語言貪吃蛇(詳解)——連結串列實現
貪吃蛇設計思路:螢幕座標:拓展功能:1.F1,F2控制加速減速 空格暫停遊戲 Esc退出2.加速每個食物得分更高先打印出遊戲介面,還有初始化蛇,蛇的節點用字串★表示,遊戲背景用■表示,因為這些字串佔兩個位元組的寬度,所以每次x,y座標的對應關係是x=y*2。在相應位置打印
對C語言執行結果(控制檯視窗)表格的實現(最基礎版)
先放張效果圖: 這就是一個簡單的表格(複雜的我辦不到!!),而這個表格的實現也是非常簡單的,就是簡單的 printf 輸出: #include <stdio.h> int main() { printf("=================================
C語言-B樹(B-樹)的完整實現
B樹的定義 B樹是一種平衡的多路查詢樹。 一顆m階B樹,或為空樹,或為滿足下列特性的m叉樹。 (1)樹中每個結點最多含有m棵子樹; (2)若根結點不是葉子結點,則至少有兩顆子樹; (3)除根之外的所有非終端結點至少有[m/2]; (4)每個非終端結點
C指標詳解與連結串列實現
一直以來,對於c語言的指標就一知半解,資料結構課程多半是用c指標實現的,所以重新學習了一下 程式碼來源:《啊哈,演算法》人民郵電出版社、中國工信出版集團 啊哈磊著 (一)指標 使用指標的原因:方便版本迭代,假設你設計的程式已經發布或者交付使用,但是你發現要做出新的修改(增加
C語言的結構體詳解(轉載只是為了查閱方便,若有侵權立刪)
C語言的結構體詳解 結構體(struct) 1、定義 一般格式為: struct 結構名 {
C語言 貪吃蛇實現(不閃屏)
不費話,直接上程式碼。VC++ 6.0可以完美執行,VS2015等版本需要做點修改,請按提示將“scanf”這些函式改成“_scanf”這樣的形式即可。 不閃屏的原理部分請參考這篇文章 程式碼只有兩百多行,很多地方都加上了註釋,有疑問可以
藍橋杯 名次判斷(詳解)--------------------------C語言——菜鳥級
/*問題描述 某場比賽過後,你想要知道A~E五個人的排名是什麼,於是要求他們每個人說了一句話。 (經典的開頭……-_-!)得了第1名的人23,說了假話;得了第5名的人不好意思,也說了假話; 為了使求解問題簡單,第3名同樣說了假話。(奇數名次說假話)
Go語言實現PoW共識演算法(詳解)
PoW呢...Proof of Work ,工作量證明機制,可能這個名字大家不熟悉,說比特幣的話,大家就熟悉了吧,沒錯,PoW就是比特幣所使用的共識機制。 通過計算一個數值( nonce ),使得拼揍上交易資料後內容的 Hash 值滿足規定的上限。在節點成功找到滿足的Has
C++練習例項————貪吃蛇(OO思想)
這是一款在vs上直接控制檯輸出的貪吃蛇遊戲,沒有使用任何圖形庫。遊戲具有多個介面,狀態轉換如下: 下面直接上程式碼: Position類,用來記錄遊戲中的座標位置: #include<iostream> using namespace std; #if
C#貪吃蛇(窗體版本)
新建 在工具箱中找到 Timer,拖拽使用,將Name改為dt,Interval(單位:毫秒)改為500 然後編寫程式碼 string key_name = "start"; //記錄鍵盤狀態 Label[] l_b =
C#貪吃蛇(WPF版)
最近寫了個貪吃蛇,雖然有很多BUG,但是還是拿出來讓大家看下! 額,我用的還是VS2010. 首先,新建專案——WPF應用程式 將 canvas設定為定義為lol 接下來是引用部分 新增 using System.Windows.Threading;
【C++】靜態分配和動態分配 堆和棧(詳解)
但是,在使用陣列的時候,總有一個問題困擾著我們:陣列應該有多大?在很多的情況下,你並不能確定要使用多大的陣列,比如上例,你可能並不知道我們要定義的這個陣列到底有多大,那麼你就要把陣列定義得足夠大。這樣,你的程式在執行時就申請了固定大小的你認為足夠大的記憶體空間。即使你知道你想利用的空間大小,但是如果因為某種特
使用java語言實現一個動態陣列(詳解)(資料結構)
廢話不多說,上程式碼 1.從類名開始(我真是太貼心了,給自己點個贊) public class Array<E> 首先陣列類需要帶有泛型,這個不多說。需要注意的是在java中,陣列只能存放同一個型別的。 2.成員變數 private int size; //陣列中元素的個數 p
【轉】 C語言文件操作詳解
pri void rfi 識別 archive format 隨機 stat 文本文 轉自:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C語言中沒有輸入輸出語句,所有的輸入輸出功能都用
[C語言]貪吃蛇_結構數組實現
log pan 實現 position .html .cn 數據類型 title ack 一、設計思路 蛇身本質上就是個結構數組,數組裏存儲了坐標x、y的值,再通過一個循環把它打印出來,蛇的移動則是不斷地刷新重新打印。所以撞墻、咬到自己只是數組x、y值的簡單比較。 二、
大前端完整學習路線(詳解)
電子商務 backbone linu 請求響應 查詢 設置 lob 服務端 php 第一階段: HTML+CSS: HTML進階、CSS進階、div+css布局、HTML+css整站開發、 JavaScript基礎: Js基礎教程、js內置對象常用方法、常見DOM樹
2018上C語言程序設計(高級)作業- 第0次作業
原來 高效 成功 加油 專業 今後 kindle 眼神 電子書 1、翻閱鄒欣老師博客關於師生關系博客,並回答下列問題 1)最理想的師生關系是健身教練和學員的關系,在這種師生關系中你期望獲得來自老師的哪些幫助? 師生間的人際關系,是在教學過程中師生交往的基礎上,通
2018上C語言程序設計(高級)作業-第1次作業
alt wid 小數 keyword earch 數組 data can 計算 一.6-1 計算兩數的和與差 1.設計思路: 1)認真讀題,弄清題目已知信息; 2)理清思路,整理組織答案; 3)輸出提交; 4)流程圖如下: 2.實驗代碼如下: v
android開發學習 ------- 【轉】 android中的單例模式 (詳解)
lan post tail -- and 使用 href details android開發 https://blog.csdn.net/u011418943/article/details/60139644 這篇文章 前因後果 都說出來了 ,值得學習。 htt
2018上C語言程序設計(高級)作業- 第2次作業
方法 語句 定義 一個 log 判斷語句 為什麽 字符數組 選擇排序法 作業要求一 : 作業要求二: 6-7 刪除字符串中數字字符 1.設計思路 (1)主要描述算法: 第一步:根據函數接口定義和要求可知本題要起實現刪除一個字符串中的所有數字字符 第二步:首先定義