贪吃蛇代码(新手)

还有一些Bug
详细思路补充上来:
首先要知道一个完整的游戏需要哪些模块,这里列举出来:

必要的一些文件(设计光标和键盘操作请了解一下Windows API) 一些必要的明示常量来表示蛇的上下左右
一系列和游戏流程有关的函数保证游戏主干部分 Sleep函数和清屏函数的应用使得游戏更流畅

<Windows.h>头文件基本应用

该头文件包含了Sleep函数(用于延迟)和system函数,同时便于与键盘进行交互

制作大体流程如下:

  1. 进场界面的绘制,使用定义的gotoxy函数控制光标位置,color函数改变颜色
  2. 游戏界面的绘制,使用循环分三次绘制边框和内部,注意横向间距为2,竖向为1
  3. 蛇身的绘制,采用链表逐个绘制蛇身部分
  4. 食物的产生,采用<time.h>头文件,使用srand函数改变种子,注意每次产生食物遍历蛇身判断是否与蛇身重合,若重合再次产生食物
  5. 采用keyboardControl函数,与键盘交互,同时根据每次交互,判断是否吃到食物,吃到食物长度+1,否则正常移动
  6. 每次移动实时显示分数和速度,采用全局变量实现
  7. ESC退出确认要求用户输入字符串,保证更安全地输入采用s_gets函数
  8. 游戏结束条件是撞到墙或者咬到自己或者自行退出,前两者用坐标实现
  9. 游戏结束后用frees函数释放内存

博主自己也是新手,如果有什么地方不对望指正,一起加油吧!

// 必要的头文件 
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <windows.h>
#include <string.h>


// 定义标记上下左右的明示常量 
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
#define ESC 5 
#define FOOD 10
// 定义表示位置的结构体类型
typedef struct snake{
	int x;
	int y;
	struct snake *next;
}snake; 
// 定义全局变量 
int score = 0; // 当前得分
int speed = 200; // 存储当前速度
int status; 
snake *tail,*head; // 存储蛇头蛇尾 
snake *food,*q;// q用于遍历链表 

HANDLE hOUT;
void gotoxy(int x,int y); // 设置光标位置 
int choice(void); // 载入游戏界面
int color(int c); // 设置字体颜色 
void printGame(void); // 打印游戏界面 
void printSnake(void); // 打印蛇身
void printFood(void); // 打印食物
void printTips(void); // 打印提示
void snakeMove(void); // 主操作函数 
int biteSelf(void); // 判断是否咬到了自己
int encounterWall(void); // 判断是否撞墙 
void keyboardControl(void); // 获取击键 
void speedUp(void); // 加速
void speedDown(void); // 减速
int endGame(void); // 结束函数; 
char *s_gets(char *st,int n); // 读取字符
void frees(snake *); // 释放内存 
 
int main(int argc, char *argv[]){
	while(1)
	{
		if(choice() == 1)
			keyboardControl();
		else
		{
			gotoxy(5,15);
			printf("按任意键返回");
			getchar(); // 去除前一个前导换行 
			while(1)
			{
				if(getchar())
				{
					system("cls");
					break;
				}
			}
		}
	}
	frees(head);
	
	return 0;
}

void gotoxy(int x,int y)
{
    COORD c;
    c.X=x;
    c.Y=y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}

int choice(void)
{
	int yourchoice; 
	// 画出界面 
	gotoxy(35,5);
	color(11);  
	printf("\t贪吃蛇大作战\n");
	printf("\n\n");
	color(13); 
	printf("\t\t★★★★★★★★  Snake!");
	printf("\t\t★★★★★★★★  Snake!");
	gotoxy(25,15);
	color(12); 
	printf("1.进入游戏\t2.查看说明\t3.退出游戏\n");
	color(11); 
	printf("请选择:");
	scanf("%d",&yourchoice);
	switch(yourchoice)
	{
		case 1:
			system("cls");
			// 初始化 
			printGame();
			printSnake();
			printFood();
			break;
		case 2:
			system("cls");
			printTips();
			break;
		case 3:
			system("cls");
			gotoxy(30,10);
			color(11); 
			printf("Bye!");
			exit(0);
		default:
			system("cls");
			printf("没有此序号,请输入1,2或3\n");
			Sleep(2000);
			system("cls");
	}
	return yourchoice;
} 
int color(int c)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);        //更改文字颜色
	return 0;
}
void printGame()
{
	int i,j;
	gotoxy(5,5);
	printf("游戏载入中...请稍后");
	Sleep(2000);
	system("cls");
	
	// 打印上下界面
	for(i = 0;i <= 50;i += 2)
	{
		gotoxy(i,0);
		printf("□");
		gotoxy(i,25);
		printf("□");
	} 
	// 打印左右界面
	for(i = 0;i <= 25;i += 1)
	{
		gotoxy(0,i);
		printf("□");
		gotoxy(50,i);
		printf("□");
	} 
	// 打印中间网格
	for(i = 1;i <= 24;i += 1)
	{
		for(j = 2;j <= 48;j += 2)
		{
			gotoxy(j,i);
			color(11);
			printf("■");	
		}
	} 
	// 打印右侧的规则和计分栏
	gotoxy(60,13);
	printf("当前分数:%d分,当前速度%d",score,speed);
	gotoxy(60,15);
	printf("用↑ ↓ ← →分别控制蛇的移动\n");
	gotoxy(60,18); 
	printf("每次获取食物加10分  按下F1加速,F2减速,空格暂停\n");
	gotoxy(60,20);
	printf("不能撞墙和咬到自己!"); 
	gotoxy(60,22);
	printf("速度不低于100,不高于300");
} 
void printSnake(void)
{
	int i; 
	// 设定蛇尾(16,13),头插入,初始向右 
	tail = (snake*)malloc(sizeof(snake));
	tail->x = 16;
	tail->y = 13;
	tail->next = NULL;
	// 设定初始蛇长是4
	for(i = 1;i <= 4;i++)
	{
		head = (snake*)malloc(sizeof(snake));
		head->next = tail;
		head->x = 16+2*i;
		head->y = 13;
		tail = head; // 头成为尾
	} 
	// 输出蛇身
	while(tail->next)
	{
		gotoxy(tail->x,tail->y);
		color(14);
		printf("★");
		tail = tail->next;	
	} 
}
void printFood(void)
{
	srand((unsigned)time(NULL)); // 利用时钟修改种子 
	food = (snake*)malloc(sizeof(snake));
	food->x = 1; // 初始化x坐标 
	while(food->x%2 && food->x)
	{
		food->x = rand()%46+2;// 2-48 
	}
	food->y = rand()%23+1; // 1-24 
	q = head; // 不改变头遍历链表 
	while(q->next) 
	{
		if(q->x == food->x && q->y == food->y)
		{
			free(food);
			printFood();
		}
		else
		{
			gotoxy(food->x,food->y);
			color(12);
			printf("●");
			break; 
		}
	}
}
void printTips(void)
{
	color(11); 
	printf("***********Tips************\n"); 
	printf("1.采用合理的速度可以获得更高的分数哦!\n");
	printf("2.一定不要撞到自己或者两边的墙!\n");
	printf("3.游戏过程中按ESC退出游戏!\n"); 
}
void snakeMove(void)
{
	snake *snakenext;
		snakenext = (snake*)malloc(sizeof(snake));
		if(biteSelf())
		{
			gotoxy(60,11);
			printf("咬到自己啦!");
			free(snakenext);
			Sleep(1500);
			system("cls"); 
			exit(0);
		}
		else if(encounterWall())
		{
			gotoxy(60,11);
			printf("撞到墙啦!"); 
			free(snakenext);
			Sleep(1500);
			system("cls"); 
			exit(0);
		}
		else
		{
			// 前两个条件判断完成才开始移动 
			Sleep(350-speed);
			if(status == UP)
			{
				snakenext->x = head->x;
				snakenext->y = head->y-1;
				snakenext->next = head;
				head = snakenext;
				q = head;
				if(snakenext->x == food->x && snakenext->y == food->y)
				{
					while(q)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					score += FOOD;
					gotoxy(60,13);
					printf("当前分数:%d分,当前速度%d",score,speed);
					printFood();
				}
				else
				{
					while(q->next->next)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					gotoxy(q->next->x,q->next->y);
					color(11);
					printf("■");
					free(q->next);
					q->next = NULL; 
				}
			}
			else if(status == DOWN)
			{
				snakenext->x = head->x;
				snakenext->y = head->y+1;
				snakenext->next = head;
				head = snakenext;
				q = head;
				if(snakenext->x == food->x && snakenext->y == food->y)
				{
					while(q)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					score += FOOD;
					gotoxy(60,13);
					printf("当前分数:%d分,当前速度%d",score,speed);
					printFood();
				}
				else
				{
					while(q->next->next)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					gotoxy(q->next->x,q->next->y);
					color(11);
					printf("■");
					free(q->next);
					q->next = NULL; 
				}
			}
			else if(status == LEFT)
			{
				snakenext->x = head->x-2;
				snakenext->y = head->y;
				snakenext->next = head;
				head = snakenext;
				q = head;
				if(snakenext->x == food->x && snakenext->y == food->y)
				{
					while(q)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					score += FOOD;
					gotoxy(60,13);
					printf("当前分数:%d分,当前速度%d",score,speed);
					printFood();
				}
				else
				{
					while(q->next->next)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					gotoxy(q->next->x,q->next->y);
					color(11);
					printf("■");
					free(q->next);
					q->next = NULL; 
				}
			}
			else if(status == RIGHT)
			{
				snakenext->x = head->x+2;
				snakenext->y = head->y;
				snakenext->next = head;
				head = snakenext;
				q = head;
				if(snakenext->x == food->x && snakenext->y == food->y)
				{
					while(q)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					score += FOOD;
					gotoxy(60,13);
					printf("当前分数:%d分,当前速度%d",score,speed);
					printFood();
				}
				else
				{
					while(q->next->next)
					{
						gotoxy(q->x,q->y);
						color(14);
						printf("★");
						q = q->next;
					}
					gotoxy(q->next->x,q->next->y);
					color(11);
					printf("■");
					free(q->next);
					q->next = NULL; 
				}
			}
		}
}
int biteSelf(void)
{
	int x = 0; // 默认未咬到自己
	q = head->next;
	// 遍历蛇身 
	while(q->next)
	{
		if(q->x == head->x && q->y == head->y)
		{
			x = 1;		
		}
		q = q->next;
	}	
	
	return x;
} 
int encounterWall(void)
{
	int x = 0; // 默认未撞到墙
	
	if(head->x == 0 || head->x == 50 || head->y == 0 || head->y == 25)
		x = 1;
	
	return x; 
}
void keyboardControl(void)
{
	status=RIGHT; // 初始蛇向右移动
	while(1)
	{
	    if(GetAsyncKeyState(VK_UP) && status != DOWN) // GetAsyncKeyState函数用来判断函数调用时指定虚拟键的状态
	    {
	        status=UP;           //如果蛇不是向下前进的时候,按上键,执行向上前进操作
		}
	    else if(GetAsyncKeyState(VK_DOWN) && status != UP) // 如果蛇不是向上前进的时候,按下键,执行向下前进操作
	    {
	        status=DOWN;
	    }
	    else if(GetAsyncKeyState(VK_LEFT)&& status != RIGHT) // 如果蛇不是向右前进的时候,按左键,执行向左前进
	    {
	        status=LEFT;
	    }
	    else if(GetAsyncKeyState(VK_RIGHT)&& status != LEFT) // 如果蛇不是向左前进的时候,按右键,执行向右前进
	    {
	        status=RIGHT;
	    }
	    if(GetAsyncKeyState(VK_SPACE))// 空格暂停 
	    {
	        while(1)
			{
				Sleep(300);
				if(GetAsyncKeyState(VK_SPACE)) // 再次按空格改变状态 
				{
					break;
				}
				
			}       
	    }
	    else if(GetAsyncKeyState(VK_ESCAPE))
	    {
	        status = ESC; // 按esc键,直接到结束界面
	        if(endGame())
	        {
	        	Sleep(500);
	        	system("cls");
				break; 
	      	}
	    }
	    else if(GetAsyncKeyState(VK_F1)) // 按F1键,加速
	    {
	        speedUp();
	        gotoxy(60,13); 
	        printf("当前分数:%d分,当前速度%d",score,speed);
	    }
	    else if(GetAsyncKeyState(VK_F2)) // 按F2键,减速
	    {
	    	speedDown();
	    	gotoxy(60,13); 
			printf("当前分数:%d分,当前速度%d",score,speed); 
	    }
	    snakeMove();
	}
}
void speedUp(void)
{
	if(speed <= 280)
		speed += 20;	
} 
void speedDown(void)
{
	if(speed >= 120)
		speed -= 20;
}
int endGame(void)
{
	char x = 0;
	char judge[5];
	
	getchar(); 
	gotoxy(60,9);
	printf("确定退出吗?(Yes/No)");
	gotoxy(60,11); 
	s_gets(judge,5);
	
	if(strcmp(judge,"Yes") == 0)
	{
		Sleep(250);
		system("cls");
		gotoxy(40,11); 
		printf("\tBye!");
		x = 1;
	}
	else
		x = 0;
	
	return x;
}
char *s_gets(char *st,int n)
{
	char *ret_val;
	char *find;
	
	gotoxy(60,11);
	ret_val = fgets(st,n,stdin);
	if(ret_val)
	{
		find = strchr(st,'\n');
		if(find)
			*find = '\0';
		else
			while(getchar() != '\n')
				continue;
	}
	
	return ret_val;
}
void frees(snake *s)
{
	snake *current = s;
	
	while(current)	
	{
		current = s;
		s = current->next;
		free(current);
	}
} 

猜你喜欢

转载自blog.csdn.net/DevXU/article/details/106623619