教你製作屬於自己的C語言版貪吃蛇!

貪吃蛇
  沒錯,就是貪吃蛇,這個你不會不知道吧。那你肯定會疑問了,還能用代碼寫貪吃蛇?當然啦,今天我就教大家寫一個屬於自己的貪吃蛇
  你所需要準備的是:一定的鏈表知識,電腦集成編譯環境CodeBlocks(最好使用該軟件,否則可能會不成功),點個關注一波~~後續有好東西,我會繼續分享的!

設計思路
  首先,要先將背景打印出來,這裏需要的函數下面會介紹。然後隨機生成蛇頭,根據蛇頭生成蛇身,並將整個蛇打印出來,然後生成食物(確保不和蛇重合),這樣,第一步就完成了。接下來,到了最主要的步驟了,蛇身移動及吃食。這裏我採用的是先清除蛇身,再打印到移動後的位置,吃食同理。而蛇的方向控制需要鍵盤控制。

調用函數
void Menu();    //初始化菜單
void Gotoxy(int x, int y);    //光標定位
void GotoChange(int x, int y);   //將■改爲空格
void GotoPrint(int x, int y);    //轉至(x,y)打印■
void CreatWall();    //生成圍牆
void CreatSnake();    //初始化生成蛇
void PrintBody();    //打印蛇身
void Initialization();    //初始化界面
void CreatFood();    //生成隨機食物
int Control();    //控制蛇
int Judge();    //評判結束
void MovingBody();   //移動蛇身
void ChangeBody(int x, int y);   //改變蛇身
void Eating();    //蛇“進食”
void End();    //結束頁面
  其中比較難理解且重要的函數可見:
gotoxy()函數——>傳送門
Control()裏的_kbhit()——>傳送門
Control()裏的_getch()——>傳送門
未列出的變色函數SetConsoleTextAttribute——>傳送門

代碼實現:

#include<stdio.h>
#include<string.h>
#include<windows.h>
#include<time.h>
#include<conio.h>

#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'

typedef struct snake
{
    int x, y;
    struct snake *next;
}SNAKE;

void Menu();       //初始化菜單
void Gotoxy(int x, int y);      //光標定位
void GotoChange(int x, int y);     //將■改爲空格
void GotoPrint(int x, int y);       //轉至(x,y)打印■
void CreatWall();       //生成圍牆
void CreatSnake();        //初始化生成蛇
void PrintBody();       //打印蛇身
void Initialization();      //初始化界面
void CreatFood();       //生成隨機食物
int Control();     //控制蛇
int Judge();        //評判結束
void MovingBody();      //移動蛇身
void ChangeBody(int x, int y);      //改變蛇身
void Eating();      //蛇“進食”
void End();     //結束頁面

char name[66];
int speed = 50, score = 0, co;
SNAKE *head, *tail;
int food_x, food_y;
char input = 1;

int main()
{
    Menu();
    CreatWall();
    CreatSnake();
    Initialization();
    CreatFood();
	if(Control() == 0)
        return 0;
    return 0;
}

void Menu()
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    Gotoxy(40, 16);
    printf("歡迎打開貪吃蛇遊戲~~~\n");
    Gotoxy(40, 17);
    printf("請輸入您的用戶名:");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    scanf("%s", name);
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
    Gotoxy(40, 19);
    printf("請您選擇遊戲難度:\n\
           \t\t\t\t\t1:小白模式\n\
           \t\t\t\t\t2:普通模式(推薦)\n\
           \t\t\t\t\t3:困難模式\n\
           \t\t\t\t\t4:極限模式\n\
           \t\t\t\t\t5:變態模式\n\
           \t\t\t\t\t6:冒險模式\n\t\t\t\t\t");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    scanf("%d", &co);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    if(co > 0 && co < 6)
        speed *= (6-co);
    else
        speed = 300;
	system("cls");
	Gotoxy(42, 14);
	printf("正在加載中~~~\n");
    Gotoxy(20, 16);
    printf("提示:\n");
    Gotoxy(24, 18);
    printf("請在英文輸入法中操作,反向移動等同於吃到自己,wasd控制p暫停\n");
    Gotoxy(36, 20);
    printf("\t全屏遊戲效果更佳喲~~~");
    Sleep(3000);
    system("cls");
}
void Gotoxy(int x, int y)
{
    COORD pos = {x, y};
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);      // 獲取標準輸出設備句柄
    SetConsoleCursorPosition(hOut, pos);        //兩個參數分別是指定哪個窗體,具體位置
}
void GotoPrint(int x, int y)
{
    Gotoxy(x, y);
    printf("■");
}
void GotoChange(int x, int y)
{
    Gotoxy(x, y);
    printf(" ");
}
void CreatWall()
{
    int i, j;
    for (i = 0; i < 36; i++)
    {
        for(j = 0; j < 72; j += 2)
        {
            if(i == 0 || i == 35 || j == 0 || j == 70)
                printf("■");
            else
                printf("  ");
        }
        printf("\n");
    }
}
void CreatSnake()
{
    srand((unsigned)time(NULL));
    head = (SNAKE*)malloc(sizeof(SNAKE));
	head->x = rand()%30+3;
	if(head->x % 2 != 0)
    {
        head->x++;
    }
	head->y = rand()%30+3;
	tail = (SNAKE*)malloc(sizeof(SNAKE));
	SNAKE *p = (SNAKE*)malloc(sizeof(SNAKE));
	SNAKE *q = (SNAKE*)malloc(sizeof(SNAKE));
	p->x = head->x;
	p->y = head->y+1;
	q->x = head->x;
	q->y = head->y+2;
	head->next = p;
	p->next = q;
	q->next = tail;
    tail->next = NULL;
}
void PrintBody()
{
    SNAKE *t = head;
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    GotoPrint(t->x, t->y);
    t = t->next;
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
	while(t->next != NULL)
    {
        GotoPrint(t->x, t->y);
        t = t->next;
    }
    Gotoxy(0, 36);
}
void Initialization()
{
	PrintBody();
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    Gotoxy(128, 2);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    printf("p:(開始/暫停)");
    Gotoxy(120, 3);
    printf("如果蛇在移動過程中,撞到牆壁或身體");
    Gotoxy(120, 4);
    printf("交叉(蛇頭撞到自己的身體)遊戲結束");
    Gotoxy(100, 12);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    printf("%s", name);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    printf(",加油加油喀~~~");
    Gotoxy(100, 18);
    printf("您目前的分數爲:");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    Gotoxy(116, 18);
    printf("%d", score);
    Gotoxy(100, 24);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    printf("小遊戲作者:");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    printf("ChrisPhantom");
}
void CreatFood()
{
    lable:
	food_y = rand()%(34) + 1;
	food_x = rand()%(67) + 2;
	if (food_x % 2 != 0)
	{
		food_x = food_x + 1;
	}
	SNAKE *t = head;
	while(1)       //遍歷排除蛇身重複
	{
		if(t->next == NULL)
            break;
		if(food_x == t->x && food_y == t->y)
		{
			goto lable;
		}
		t = t->next;
	}
	Gotoxy(food_x, food_y);
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
	printf("⊙");
}
int Control()
{
	while (1)
	{
		if (Judge() == 0)
            return 0;
		if (_kbhit())
		{
			input = _getch();
		}
		MovingBody();
		Eating();
	}
	return 1;
}
int Judge()
{
    if (head->x == 0 || head->x == 70 || head->y == 0 || head->y == 35)     //撞到牆壁
    {
        End();
        return 0;
    }
	SNAKE *p = head->next;
	while (1)
	{
		if (p->next == NULL)
            break;
		if (head->x == p->x && head->y == p->y)     //身體交叉
        {
            End();
            return 0;
        }
		p = p->next;
	}
	return 1;
}
void MovingBody()       //通過先清空後打印實現動畫效果
{
    int x = head->x, y = head->y;
	SNAKE *p = head;
	while (1)
	{
		if (p->next == NULL)
            break;
		GotoChange(p->x, p->y);
		p = p->next;
	}
	switch (input)
	{
		case up:
			head->y -= 1;
			ChangeBody(x, y);
			break;
		case down:
			head->y += 1;
			ChangeBody(x, y);
			break;
		case left:
			head->x -= 2;
			ChangeBody(x, y);
			break;
		case right:
			head->x += 2;
			ChangeBody(x, y);
			break;
		case stop:
			break;
	}
	PrintBody();
	Sleep(speed);
}
void ChangeBody(int x, int y)
{
    SNAKE *p = head->next;
	int mid1, mid2, tmid1, tmid2;
	mid1 = p->x;
	mid2 = p->y;
	while (1)
	{
		if (p->next->next == NULL)
            break;
		tmid1 = p->next->x;
		tmid2 = p->next->y;
		p->next->x = mid1;
		p->next->y = mid2;
		mid1 = tmid1;
		mid2 = tmid2;
		p = p->next;
	}
	p = head->next;
	//if (p->next!= NULL)
	{
		p->x = x;
		p->y = y;
	}
}
void Eating()
{
    if (head->x == food_x && head->y == food_y)
	{
	    printf("\a");
		CreatFood();
		SNAKE *t = (SNAKE*)malloc(sizeof(SNAKE));
		SNAKE *p;
		p = head;
		while (1)
		{
			if (p->next->next == NULL)
                break;
			p = p->next;
		}
		p->next = t;
		t->next = tail;
		score += 10;
		if(co == 6 && speed > 40)
        {
            speed -= 20;
        }
		Gotoxy(116, 18);
		HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
        SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
		printf("%d", score);
	}
}
void End()
{
    system("cls");
    Gotoxy(56, 14);
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    printf("%s,", name);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    printf("您的得分爲:");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    printf("%d", score);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    Gotoxy(56, 16);
    if(score <= 30)
        printf("不要氣餒,繼續加油啊 ~_~");
    else if(score <= 70)
        printf("你已經很不錯啦,是不是還可以更厲害呢 @_@");
    else if(score <=120)
        printf("你真是超級厲害啊,已經超過大多數人啦 ^_^");
    else
        printf("難道你...你就是傳說中的dalao !_!");
    Gotoxy(48, 19);
    printf("小遊戲作者:");
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
    printf("ChrisPhantom(沒錯就是我ChrisPhantom本人了,手動滑稽)");
    Gotoxy(48, 20);
    SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
    printf("如果喜歡的話,就給我點個贊吧~~~");
    Gotoxy(48, 22);
	system("pause");
}

參考資料
https://blog.csdn.net/qq_40935723/article/details/86553391
https://blog.csdn.net/qq_40953281/article/details/79315254
https://mbd.baidu.com/newspage/data/error
由於其中部分代碼的註釋未詳盡的解釋,不明白的可以私信諮詢。喜歡的話麻煩點個贊分享一下啦。

如果覺得本碼足夠規整而又不清楚規範,可查看另一帖子《C語言代碼規範》–>傳送門

感謝師傅來訪,技術不精,請勿吐槽,如有問題請留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章