贪吃蛇---C语言实现

前言:贪吃色算是编程入门中非常经典的练习案例之一了,算是对我之前学C的一个小小总结,界面方面参考了一些网上好看的格式,自己实现了具体功能

首先
必备知识栈:(由于是用C实现,C的基础就不废话了)
1.链表相关知识的熟练使用
2.动态内存的简单使用与释放方法
3.随机数的生成与保存
4.监听键盘函数的使用
5.window.h中基本的控制台函数
6.时间函数的简单应用

注:我没有使用相关图形函数,图形都是依靠控制台打印
感兴趣的朋友可以尝试利用工具将其图形化

其次:
下面是实现的具体代码:(有详细的注释解释)

#pragma comment(lib,"user32.lib")
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<time.h>
#include<string.h>
#include<math.h>
#pragma comment(lib,"winmm.lib")

#define U 1
#define D 2
#define L 3
#define R 4

typedef struct Node
{
	int x;
	int y;
	struct Node *next;
} Node;

Node *head,*food,*index;            //头,食物,游标
void snake_create(); 				//蛇 
void wall_create();					//墙 
void Pos(int,int);					//光标位置 
void game_description();			//游戏说明界面
void snake_move();					//移动控制
void game_control();				//游戏控制
void start_game();					//开始游戏
void pause_game();					//暂停游戏
void exit_game();					//退出游戏
void bitself();						//咬自己
void bitwall();						//撞到墙
void spawn_food();					//出现食物
int score = 0,	add = 10,	death_type,		direction = R,	speedtime = 200;

void Pos(int x, int y)		//设置光标位置 
{
	COORD pos;
	HANDLE hOutput;
	pos.X = x;
	pos.Y = y;
	hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOutput,pos);
}

void game_description()			//游戏描述 
{
	Pos(40, 14);
	printf("欢迎进入贪吃蛇游戏!\n\n");
	system("pause");
	system("color de");
	system("cls");
	Pos(10,14);
	printf("你可以用键盘上的:上↑,下↓,左←,右→。来控制小蛇方向\n");
	Pos(10,15);
	printf("吃到食物后身体会变长!\n");
	Pos(10,16);
	printf("如果你的小蛇碰到墙壁或者吃到自己,游戏就会结束哦!\n");
	system("pause");
	system("cls");
	wall_create();				//生成墙壁 
	snake_create();				//生成小蛇 
	spawn_food();				//生成食物 
}

void wall_create()			//生成墙 
{
	int i;
	for(i = 0;i < 58; i += 2) //打印上下边框 
	{
		Pos(i,0);
		printf("■");
		Pos(i,26);
		printf("■");
	}
	for(i = 1;i < 26;i++)	//打印左右边框 
	{
		Pos(0,i);
		printf("■");
		Pos(56,i);
		printf("■"); 
		Pos(70,10);
		printf("当前分数");
	}	
}

void snake_create()			//生成蛇 
{
	Node *tail;
	int i;
	tail = (Node*)malloc(sizeof(Node));
	tail -> x = 24;
	tail -> y = 5; 
	tail -> next = NULL;
	for(i = 1; i <= 4; i++)
	{
		head = (Node*)malloc(sizeof(Node));
		head -> next = tail;
		head -> x = 24 + 2 * i;
		head -> y = 5;
		tail = head;
	}
	while (tail != NULL)			//由头到尾,输出蛇身 
	{
		Pos(tail -> x, tail -> y);
		printf("◆");
	    tail = tail -> next; 	
	}
}

void spawn_food()			//生成食物 
{
	if(food != NULL)		//避免食物重复生成 
	{
		return;
	}
	Node* food_1 = (Node*)malloc(sizeof(Node));
	food_1 -> x = rand() % 52 + 2;
	food_1 -> y = rand() % 24 + 1;		//确保食物在墙的范围内 
	while( (food_1 -> x) % 2 != 0)
	{
		food_1 -> x = rand() % 50 + 2;
	}
	index = head;
	while( index != NULL)
	{
		if(food_1 -> x == index -> x && food_1 -> y == index -> y)		//小蛇吃到食物 
		{
			free(food_1);	//吃掉食物后,释放内存,食物消失
			spawn_food();	//重新生成
			break;			//退出判断 
		}
		index = index -> next;		 
	}
	food = food_1;
	Pos(food -> x,food -> y);
	printf("●");
}

void snake_move() 		//蛇的移动
{
	bitwall();
	Node *nexthead = (Node*)malloc(sizeof(Node));
	switch(direction)
	{
		case U:
			nexthead -> x = head -> x;
			nexthead -> y = head -> y-1;			//坐标轴的原点在命令框的左上角 
			break;
		case D:
			nexthead -> x = head -> x;
			nexthead -> y = head -> y+1;
			break;
		case L:
			nexthead -> x = head -> x-2;			//我们使用的字符是占三个字节的,所以需要至少两个字宽才能显示
			nexthead -> y = head -> y;
			break;
		case R:
			nexthead -> x = head -> x+2;
			nexthead -> y = head -> y;
			break;
	}
	nexthead -> next = head;
	head = nexthead;
	index = head;
	bitself();
	if(nexthead -> x == food -> x && nexthead -> y == food -> y)
	{
		while( index != NULL)
		{
			Pos(index -> x, index -> y );
			printf("◆");
			index = index -> next;
		}
		score += add;
		free(food);
		food = NULL;  //吃到食物就将其赋空
		spawn_food();
	}
	else				//前进 
	{
		while(index -> next -> next != NULL)
		{
			Pos(index -> x, index -> y);
			printf("◆");
			index = index -> next; 
		}
		Pos(index -> next ->x ,index -> next -> y);
		printf(" ");
		free(index -> next);
		index -> next = NULL;
	}	
} 

void game_control()		//控制小蛇 
{
	Pos(64, 15);
	printf("不能碰到墙,不能咬到自己\n");
	Pos(64,16);
	printf("用↑↓←→控制蛇的方向");
	Pos(64,17);
	printf("F1为加速,F2为减速\n");
	Pos(64,18);
	printf("ESC:退出游戏      space:暂停游戏");
	direction = R;
	while(1)
	{
		Pos(64, 10);
		printf("得分:%d ",score);
		Pos(64, 11);
		printf("当前食物分值:%d分",add);
		if(GetAsyncKeyState(VK_UP) && direction != D)
		{
			direction = U;
		}
		else if(GetAsyncKeyState(VK_DOWN) && direction != U)
		{
			direction = D;
		}
		else if(GetAsyncKeyState(VK_RIGHT) && direction != L)
		{
			direction = R;
		}
		else if(GetAsyncKeyState(VK_LEFT) && direction != R)
		{
			direction = L;
		}
		else if(GetAsyncKeyState(VK_ESCAPE))
		{
			death_type = 3;
			break;
		}
		else if(GetAsyncKeyState(VK_SPACE))
		{
			pause_game();
		}
		else if(GetAsyncKeyState(VK_F1))		//加速 
		{
			if(speedtime > 50)
			{
				speedtime -= 30;
				add += 2;
				if(speedtime == 320)
				{
					add = 2;
				}
			}
		}
		else if(GetAsyncKeyState(VK_F2))		//减速 
		{
			speedtime += 30;
			add -= 2;
			if(speedtime == 350)
			{
				add = 1;
			}
		}
		Sleep(speedtime);
		snake_move();
	 } 
}

void pause_game()			//暂停 
{
	while(1)
	{
		Sleep(300);
		if(GetAsyncKeyState(VK_SPACE))
		{
			break;
		}
	}
}

void bitwall()			//撞墙 
{
	if(head -> x == 0 || head -> x == 56 || head -> y == 0 || head -> y == 26)
	{
		death_type = 1;
		exit_game(); 
	}
}

void bitself()			//咬自己 
{
	Node *self = head-> next;
	while(self != NULL)
	{
		if(self -> x == head -> x && self -> y == head -> y)
		{
			death_type = 2;
			exit_game();
		}
		self = self -> next;
	}
}

void exit_game()		//退出游戏 
{
	system("cls");
	Pos(24, 12);
	if(death_type == 1)
	{
		printf("对不起,小蛇撞到墙了,游戏结束!"); 
	}
	else if(death_type == 2)
	{
		printf("对不起,小蛇咬到自己了,游戏结束!");
	} 
	else if(death_type == 3)
	{
		printf("你结束了游戏!");
	}
	Pos(24, 13);
	printf("你的得分是%d\n",score);
	getchar();
	exit(0);
}

int main()
{
	system("title ★★★贪吃蛇★★★");
	system("mode con cols= 100 lines = 30"); 	
	game_description();
	game_control();
	system("pause");		

}

下面是代码的实现图片:

在这里插入图片描述

进入
在这里插入图片描述
开始之后,按空格键暂停
在这里插入图片描述
可以按F1和F2实现速度的改变
在这里插入图片描述
游戏结束界面

小总结:
参考了网上的小思路,可以按F1 和 F2 来实现小蛇的加速和减速,这个其实是保存了一个速度,通过函数的来改变即可,不过却很巧妙。
总体来说,贪吃蛇难度不大,但其需要我们对基本知识有一个较为全面的把握,不失为作为全面回顾的好案例,对于C初学者而言比较友好。

END

附上一只超级可爱的小猫咪,真的超级可爱
在这里插入图片描述

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值