<tr id="ieeco"><small id="ieeco"></small></tr>
<acronym id="ieeco"></acronym>

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(".@.@");

	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;
}

?

?

?

已標記關鍵詞 清除標記
相關推薦
用windows api 做的貪吃蛇 #include<Windows.h> #include"resource.h" #include"Node.h" #include<stdlib.h> #include<time.h> TCHAR szAppname[] = TEXT("Snack_eat"); #define SIDE (x_Client/80) #define x_Client 800 #define y_Client 800 #define X_MAX 800-20-SIDE //點x的范圍 #define Y_MAX 800-60-SIDE //點y的范圍 #define TIME_ID 1 #define SECOND 100 #define NUM_POINT 10 //點的總個數 #define ADD_SCORE 10 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { HWND hwnd; //窗口句柄 MSG msg; //消息 WNDCLASS wndclass; //窗口類 HACCEL hAccel;//加速鍵句柄 wndclass.style = CS_HREDRAW | CS_VREDRAW; //窗口的水平和垂直尺寸被改變時,窗口被重繪 wndclass.lpfnWndProc = WndProc; //窗口過程為WndProc函數 wndclass.cbClsExtra = 0; //預留額外空間 wndclass.cbWndExtra = 0; //預留額外空間 wndclass.hInstance = hInstance; //應用程序的實例句柄,WinMain的第一個參數 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); //設置圖標 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); //載入預定義的鼠標指針 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //設置畫刷 wndclass.lpszMenuName = szAppname; //設置菜單 wndclass.lpszClassName = szAppname; //設置窗口類的名字 if (!RegisterClass(&wndclass))//注冊窗口類 { MessageBox(NULL, TEXT("這個程序需要windows NT!"), szAppname, MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppname, TEXT("Snack_eat"),//CreateWindow函數調用時,WndProc將受到WM_CREATE WS_OVERLAPPEDWINDOW&~WS_THICKFRAME& ~WS_MAXIMIZEBOX,//普通的層疊窗口&禁止改變大小&禁止最大化 CW_USEDEFAULT, //初始x坐標(默認) CW_USEDEFAULT, //初始y坐標 x_Client, //初始x方向尺寸 770 y_Client, //初始y方向尺寸 750 NULL, //父窗口句柄 NULL, //窗口菜單句柄 hInstance, //程序實例句柄 WinMain函數中第二個參數 NULL); //創建參數 ShowWindow(hwnd, iCmdShow);//顯示窗口,iCmdShow是WinMain的第四個參數,決定窗口在屏幕中的初始化顯示形式,例:SW_SHOWNORMAL表示正常顯示 UpdateWindow(hwnd);//使窗口客戶區重繪,通過向WndProc發送一條WM_PAINT消息而完成的 hAccel = LoadAccelerators(hInstance, szAppname);//加載加速鍵 while (GetMessage(&msg
??2020 CSDN 皮膚主題: 游動-白 設計師:白松林 返回首頁
彩票送彩金