教你制作属于自己的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语言代码规范》–>传送门

感谢师傅来访,技术不精,请勿吐槽,如有问题请留言。

上一篇:vscode插件开发②-主题插件:colors配置项


下一篇:vscode护眼绿+python环境搭建