C语言实现经典小游戏贪吃蛇

纯c语言写的小游戏,本人才疏学浅,代码有很多不足,仅供给初学者参考。

实现功能:

  • ↑ ↓ ← →分别用来控制上下左右四个方向
  • 空格暂停
  • esc退出游戏
  • f1加速, f2 减速
  • 蛇的长度越长,速度越快(速度有上限)
  • 食物颜色随机
  • 撞墙死/咬到自己死

不足之处:

  • 实现了蛇撞墙和撞到自己两种死亡判断,但是没有实现游戏胜利。
  • 蛇移动的时间和食物出现的时间固定,没有实现游戏难度的选择。

运行结果展示:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码如下:

头文件(snack.h)

#ifndef __SNACK_H__
#define __SNACK_H__

#define _CRT_SECURE_NO_WARNINGS 1

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define  WALL "▓"
#define SNACK "●"
#define FOOD "★"

#define INIT_X 10
#define INIT_Y 20
#define INIT_LONG 4

enum Direction 
{
	UP = 1,	//上
	DOWN,	//下
	LEFT,	//左
	RIGHT	//右
};

typedef enum GameStatus	//游戏状态
{
	OK,				//正常
	NORMAL_END,		//正常结束
	KILL_BY_WALL,	//撞墙
	KILL_BY_SELF	//咬到自己
};

typedef struct SnackNode	//表示蛇身节点
{
	int x;
	int y;
	struct SnackNode* _pNext;
}SnackNode, *pSnackNode;

typedef struct Snack
{
	pSnackNode _psnack;//位置
	pSnackNode _pfood;//食物位置
	int _TotalScore; //得分
	int _AddScore;	//增加分数
	int _SleepTime;
	enum Direction _Dir;
	enum GameStatus _Status;
}Snack, *pSnack;


void setpos (int x, int y);//控制光标位置
int WelcomeToGame_1 ();//欢迎界面1
void WelcomeToGame_2 ();//欢迎界面2
void CreateMap ();//初始化地图
void InitSnack (pSnack ps);//初始化蛇
void CreateFood (pSnack ps);//打印食物
void GameStart (pSnack ps);//游戏开始
void SnackMove(pSnack ps);//蛇移动
void Killed_By_Wall(pSnack ps);//撞墙死
void Collide_Self(pSnack ps);咬到自己死
void AboutGame (pSnack ps);//游戏说明
int color(int x);	//改变字体颜色
int GetLength (pSnack ps);//获取蛇的长度
void Exit_Game(pSnack snack);//退出游戏

#endif

主要函数(main.c)

#include "snack.h"

void setpos (int x, int y)
{
	COORD pos = {0};
	pos.X = x;
	pos.Y = y;
	SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), pos);
}

int WelcomeToGame_1 ()
{
	int i = 0;
	system ("mode con cols=100 lines=30");	//设置界面大小
	system ("title 贪吃蛇");
	setpos (38, 8);
	color (11);
	printf ("贪吃蛇xiao游戏\n");
	setpos (38, 13);
	printf ("1、开始游戏");
	setpos (38, 15);
	printf ("2、退出");
	setpos (88, 28);
	printf ("2018/08/26");
	
	setpos (38, 17);
	printf ("请选择:");
	scanf ("%d", &i);
	system ("cls");
	
	return i;
}

void WelcomeToGame_2 ()
{
	color (11);
	setpos (32, 11);
	printf ("提示:");
	setpos (35, 13);
	printf ("用↑↓←→控制蛇的移动方向,f1加速,f2减速");
	setpos (35, 15);
	printf ("速度越快,得分越多");
	setpos (35, 28);
	printf ("LOADING...");
	Sleep (2500);
	system ("cls");
}

void CreateMap ()
{
	
	int i = 0;
	color (15);
	//上边界
	for (i=0; i<=58; i+=2)
	{
		setpos (i, 0);
		printf (WALL);
	}
	//左边界
	for (i=0; i<30; i++)
	{
		setpos (0, i);
		printf (WALL);
	}
	//下边界
	for (i=2; i<=58; i+=2)
	{
		setpos (i, 29);
		printf (WALL);
	}
	//右边界
	for (i=1; i<29; i++)
	{
		setpos (58, i);
		printf (WALL);
	}
}

pSnackNode BuySnackNode ()
{
	pSnackNode cur = (pSnackNode)malloc (sizeof (SnackNode));
	if (cur == NULL)
	{
		printf ("创建蛇身节点出错,游戏结束");
		exit (1);
	}
	cur ->x = 0;
	cur ->y = 0;
	cur ->_pNext = NULL;
	return cur;
}

void print_snack(pSnack ps)
{
	pSnackNode cur = ps->_psnack;
	while (cur)
	{
		setpos (cur->x, cur->y);
		color (14);
		printf (SNACK);
		cur = cur->_pNext;
	}
	color (12);
}
void InitSnack (pSnack ps)
{
	int i = INIT_LONG;
	pSnackNode cur = NULL;
	pSnackNode first = (pSnackNode)malloc (sizeof (SnackNode));
	if (first == NULL)
	{
		printf ("创建蛇头节点出错,游戏结束");
		exit (1);
	}
	first->x = INIT_X;
	first->y = INIT_Y;
	first->_pNext = NULL;
	while (--i)
	{
		cur = BuySnackNode ();
		cur ->x = first->x + 2;
		cur->y = first->y ;
		cur->_pNext = first;
		first = cur;
	}
	ps->_Dir = RIGHT;
	ps->_psnack = first;
	ps->_AddScore = 10;
	ps->_SleepTime = 200;
	ps->_TotalScore = 0;
	ps->_Status = OK;
	print_snack(ps);
}


void CreateFood (pSnack ps)
{
	int x = 0; 
	int y = 0;
	int col = 0;
	pSnackNode snack = ps ->_psnack ;
	pSnackNode food = BuySnackNode();
	y = rand()% 28 + 1;
	do
	{
		x = rand ()% 55 + 2;
	}while ((x%2) != 0);

	food ->x = x;
	food ->y = y;

	while (snack)
	{
		if (food->x == snack->x && food->y == snack->y)
		{
			break;
		}
		else
		{
			snack = snack->_pNext;
		}
	}
	if (snack == NULL)
	{
		ps->_pfood = food;
		setpos (food->x, food->y);
		col = rand() % 15+1;
		color (col);
		printf (FOOD);
	}
	else
	{
		CreateFood (ps);
	}
	
}

void Killed_by_Self(pSnack ps)
{
	pSnackNode cur = ps->_psnack->_pNext;
	while (cur != NULL)
	{
		if (cur->x == ps->_psnack ->x  &&  cur->y == ps->_psnack ->y)
		{
			setpos (18, 21);
			printf ("很遗憾, 你把自己给咬死了!!!\n");
			ps->_Status = KILL_BY_SELF;
			break;
		}
		cur = cur->_pNext;
	}
	
}

void Killed_By_Wall(pSnack ps)
{
	if (ps->_psnack ->x == 0 || ps->_psnack ->x == 58 || ps->_psnack->y == 29 || ps->_psnack ->y == 0)
	{
		setpos (18, 21);
		printf ("很遗憾,你撞墙了!!!\n");
		ps->_Status = KILL_BY_WALL;
	}
	
}

void GameStart (pSnack ps)
 {
	int i = 0;
	do 
	{
		AboutGame (ps);
		//检测是否从键盘上按下一个值

		if(GetAsyncKeyState(VK_UP) && ps->_Dir != DOWN) //上
		{
			ps->_Dir = UP;
		}

		if(GetAsyncKeyState(VK_DOWN) && ps->_Dir != UP)	//下
		{
			ps->_Dir = DOWN;
		}


		if(GetAsyncKeyState(VK_LEFT) && ps->_Dir != RIGHT)	//左
		{
			ps->_Dir = LEFT;
		}


		if(GetAsyncKeyState(VK_RIGHT) && ps->_Dir != LEFT)	//右
		{
			ps->_Dir = RIGHT;
		}

		if(GetAsyncKeyState(VK_ESCAPE))//退出
		{
			ps->_Status = NORMAL_END;
		}

		if(GetAsyncKeyState(VK_F1))//加速
		{
			if(ps->_SleepTime > 50)
			{
				ps->_SleepTime -= 30;
			}
			ps->_AddScore += 5;
		}

		if(GetAsyncKeyState(VK_F2))//减速
		{
			if(ps->_SleepTime <= 500)
			{
				ps->_SleepTime += 50;
				if(ps->_AddScore != 6)
					ps->_AddScore -= 6;
				else
					ps->_AddScore = 6;
			}
		}
		if(GetAsyncKeyState(VK_SPACE))//暂停
		{
			while(1)
			{
				Sleep(100);
 				if(GetAsyncKeyState(VK_SPACE))
				{
					break;
				}
			}
		}
		Sleep(ps->_SleepTime);
  		SnackMove(ps);
		Killed_By_Wall(ps);
		Killed_by_Self(ps);

	}while (ps->_Status == OK);
	setpos (18, 23);
	printf ("请稍后...");
	Sleep (2500);
	system ("cls");
	setpos (45, 10);
	printf ("GAME OVER");
	setpos (45, 15);
	printf ("总分:%d", ps->_TotalScore);
	setpos (80, 28);
	system ("pause");

}

void Eat_Food(pSnack ps)
{
	//分数增加
	ps->_TotalScore += ps->_AddScore;
	
	//吃掉食物后吧食物销毁
	free (ps->_pfood );
	ps->_pfood = NULL;

	//打印蛇
	setpos (ps->_psnack ->x, ps->_psnack ->y);
	print_snack (ps);

	//在生成新的食物
	CreateFood (ps);
	//每吃一个食物,速度增加
	if (ps->_SleepTime >= 100)
	{
		ps->_SleepTime -= 10;
		ps->_AddScore += 5;
	}

}

void Not_Eat_food(pSnack ps)	// 没有吃东西,长度不变,只需要把最后一个节点处打印成空格,在销毁掉最后一个节点
{
	pSnackNode cur = ps->_psnack;
	while (cur->_pNext ->_pNext != NULL)
	{
		cur = cur->_pNext;
	}
	
	setpos (cur->_pNext ->x, cur->_pNext->y);	
	printf (" ");

	free (cur->_pNext);
	cur->_pNext = NULL;
	//打印蛇
	setpos (ps->_psnack->x, ps->_psnack->y);
	print_snack (ps);

}
void SnackMove (pSnack ps)
{
	pSnackNode cur = BuySnackNode ();
	switch (ps->_Dir)
	{
	case UP:
		{
			cur->x = ps->_psnack ->x;
			cur->y = ps->_psnack ->y-1;
			cur->_pNext = ps->_psnack ;
			ps->_psnack = cur;
			if (cur->x == ps ->_pfood ->x && cur->y == ps->_pfood->y)
			{
				Eat_Food(ps);
			}
			else
			{
				Not_Eat_food(ps);
			}
		}
		break;
	case DOWN:
		{
			cur->x = ps->_psnack ->x;
			cur->y = ps->_psnack ->y+1;
			cur->_pNext = ps->_psnack ;
			ps->_psnack = cur;
			if (cur->x == ps ->_pfood ->x && cur->y == ps->_pfood->y)
			{
				Eat_Food(ps);
			}
			else
			{
				Not_Eat_food(ps);
			}
		}
		break;
	case LEFT:
		{
			cur->x = ps->_psnack ->x-2;
			cur->y = ps->_psnack ->y;
			cur->_pNext = ps->_psnack ;
			ps->_psnack = cur;
			if (cur->x == ps ->_pfood ->x && cur->y == ps->_pfood->y)
			{
				Eat_Food(ps);
			}
			else
			{
				Not_Eat_food(ps);
			}
		}
		break;
	case RIGHT:
		{
			cur->x = ps->_psnack ->x+2;
			cur->y = ps->_psnack ->y;
			cur->_pNext = ps->_psnack ;
			ps->_psnack = cur;
			if (cur->x == ps ->_pfood ->x && cur->y == ps->_pfood->y)
			{
				Eat_Food(ps);
			}
			else
			{
				Not_Eat_food(ps);
			}
		}
		break;
	}
}

void AboutGame (pSnack ps)
{
	color (2);
	setpos (65, 9);
	printf ("游戏说明:");
	setpos (68, 11);
	printf ("控制方向:↑↓←→");
	setpos (68, 13);
	printf ("暂停:空格");
	setpos (68, 15);
	printf ("退出游戏:esc");
	setpos (68, 17);
	printf ("f1加速,f2减速");
	setpos (68, 19);
	printf ("分数:+%d", ps->_AddScore);
	color (11);
}

int color(int c)	//改变字体颜色
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);        //更改文字颜色
	return 0;
}

void Exit_Game(pSnack ps)
{
	pSnackNode cur = ps->_psnack;
	pSnackNode pre = NULL;
	while (cur != NULL)
	{
		pre = cur;
		cur = cur->_pNext;
		free (pre);
		pre = NULL;
	}
}

功能测试test.c

#include "snack.h"

void test ()
{
	int i = 0;
	int j = 0;
	Snack snack;
	srand ((unsigned)time(NULL));

	do
	{

		//开始界面
		i = WelcomeToGame_1 ()-2;
			switch (i)
			{
			case -1:
				{
					 WelcomeToGame_2 ();
					//构造地图(边界)
					CreateMap ();
					//初始化蛇
					InitSnack (&snack);
					//构造食物	
					CreateFood (&snack);
					//开始游戏
					GameStart (&snack);
				}
				break;
			case 0:
				setpos (38, 15);
				printf ("退出游戏!!\n");
				Exit_Game(&snack);
				break;
			default :
				setpos (38, 15);
				printf ("你的选择有误,2s后请重新选择...");
				Sleep (2000);
				break;
			}
	}while (i);
	setpos (66, 28);
	system ("pause");
}

void test_food ()
{
	int i = 0;
	Snack snack;
	WelcomeToGame_2 ();
	//构造地图(边界)
	CreateMap ();
	//初始化蛇
	InitSnack (&snack);
	//构造食物	
	for (; i<100; ++i)
	{
		CreateFood (&snack);
		Sleep (500);
	}
}

int main()
{
	test ();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/A__B__C__/article/details/82951798