c/c++ 贪吃蛇创意小游戏

#c/c++ 贪吃蛇小游戏
这是siren的第一个C语言小游戏,一起来看看吧。
##代码实现
先来看看头文件

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

//方向 上下左右
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4

//蛇默认的移动方向
int direction = RIGHT;
//睡眠时间
int sleepTime = 350;

//链表节点类型声明
typedef struct _snake_t{
	//数据域
	int x; 
	int y;

	struct _snake_t* next;//指针域
}snake_t;

//设置文本的颜色
int setColor(int c);

//设置光标的位置
int gotoXY(int x, int y);

//绘制字符画-蛇
int printfsnake(void);

//欢迎界面
int welcomeGame();

//游戏帮助界面
int aboutGame(void);

//绘制游戏地图
int printMap(void);

//显示分数和提示信息
int showScoreTips(void);

//从文件中读取最高分
int readFile(void);

//初始化蛇
int initSnake(void);

//随机食物
int randFood(void);

//蛇的移动
int moveSnake(void);

//通过按键实现蛇的移动
int moveKeyControl(void);

//加速蛇的移动
int speedUp(void);

//减速蛇的移动
int speedDown(void);

//判断是否撞墙 撞墙返回1 否则返回0
int isHitWall();

//判断是否咬到自己 咬到自己返回1 否则返回0
int isBitSelf();

//游戏失败边框
void failGameUi();

//结束游戏
int endGame(void);

//将最高分写入文件中
int writeFile(int score);

//销毁蛇
int destorySnake(void);

##代码实现2
接下来是源文件

#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"

//得分
int score = 0;

//吃掉每一个食物的得分
int add = 1;

//结束的标志
int endStatus = 0;

//链表的头指针
snake_t* head = NULL;

//食物的节点指针
snake_t* foodNode = NULL;

int main()
{
	int choice = 0;

	//设置控制台宽高
	system("mode con cols=100 lines=30");

	//设置随机种子
	rand(time(NULL));

	//循环接受用户选择
	while (1)
	{
		//显示欢迎页面
		choice= welcomeGame();

		switch (choice)
		{
		case 1:
			//printf("开始游戏");
			printMap();//打印地图
			//showScoreTips();//显示提示信息
			initSnake();//初始化蛇
			randFood();//随机食物
			//通过按键实现蛇的移动
			moveKeyControl();
			break;
		case 2:
			aboutGame();
			break;
		case 3:
			//printf("退出游戏");
			//系统提供的函数 退出程序
			exit(0);
			break;
		default:
			setColor(12);
			gotoXY(45, 28);
			printf("输入非法,按下回车键继续。");
			//按任意键
			getchar();
		}
		//按下回车键继续
		getchar();
	}
	
	system("pause");
	return 0;
}

//设置文本的颜色
int setColor(int c)
{
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c);
	return 0;
}

//设置光标的位置
int gotoXY(int x, int y)
{
	//坐标结构体类型
	COORD c;
	//横坐标 纵坐标
	c.X = x;
	c.Y = y;

	//STD_OUTPUT_HANDLE 表示标准输出
	//GetStdHandle(STD_OUTPUT_HANDLE) 获取当前标准输出句柄
	//c 坐标值
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
	return 0;
}

//绘制字符画-蛇
int printfsnake(void)
{
	//清屏
	system("cls");

	gotoXY(35, 1);
	setColor(6);
	printf("/^\\/^\\"); //蛇眼睛
	
	gotoXY(34,2);
	printf("|__|  o|"); //蛇眼睛

	gotoXY(33, 2);
	setColor(2);
	printf("_"); 

	gotoXY(25,3);
	setColor(12);
	printf("\\/"); //蛇信

	gotoXY(31, 3);
	setColor(2);
	printf("/"); 

	gotoXY(37,31);
	setColor(6);
	printf("\\_/"); //蛇眼睛

	gotoXY(41, 3);
	setColor(10);
	printf("\\"); 

	gotoXY(26,4);
	setColor(12);
	printf("\\___"); //舌头

	gotoXY(32,4);
	printf("________/"); 

	gotoXY(31,4);
	setColor(2);
	printf("|"); 

	gotoXY(43,4);
	setColor(10);
	printf("\\"); 

	gotoXY(32,5);
	setColor(2);
	printf("\\______"); //蛇嘴

	gotoXY(44,5);
	setColor(10);
	printf("\\"); 

	gotoXY(39,6);
	printf("|      |               \\"); //下面是蛇身

	gotoXY(38,7);
	printf("/      /                 \\");

	gotoXY(37,8);
	printf("/      /                  \\ \\");

	gotoXY(35,9);
	printf("/      /                     \\  \\");

	gotoXY(34,10);
	printf("/      /                        \\  \\");

	gotoXY(33,11);
	printf("/      /            _----_         \\  \\");

	gotoXY(32,12);
	printf("/      /          _-~    ~-_          |   |");

	gotoXY(31,13);
	printf("(      (        _-~  _--_   ~-_       _/    |");

	gotoXY(32, 14);
	printf("\\      ~-___-~    _-~   ~-_    ~~_~~      /");

	gotoXY(33, 15);
	printf("~-_           _-~         ~-_        _-~");

	gotoXY(35,16);
	printf("~--______-~                ~-___-~");

	return 0;
}

int welcomeGame()
{
	printfsnake();
	
	setColor(11);
	gotoXY(45,18);
	printf("欢迎来到贪吃蛇游戏!");

	int i, j;
	int choice;

	//绘制边框
	setColor(14);
	//控制行
	for (i = 20; i <= 26; i++)
	{
		//控制列
		for (j = 27; j <= 74; j++)
		{
			//输出上下边框
			if (i == 20 || i == 26)
			{
				gotoXY(j, i);
				printf("-");
			}
			//输出左右边框
			if (j == 27 || j == 74)
			{
				gotoXY(j, i);
				printf("|");
			}
			else
				printf(" ");
		}
	}

	//输出菜单选项
	//设置文本属性
	setColor(12);

	gotoXY(35, 22);
	printf("1.开始游戏");

	gotoXY(55, 22);
	printf("2.游戏说明");

	gotoXY(35, 24);
	printf("3.退出游戏");

	gotoXY(27, 27);
	printf("请选择[1,2,3]:");

	scanf("%d", &choice);

	return choice;
}

int aboutGame(void)
{
	int i = 0,j = 0;

	//清屏
	system("cls");

	//输出标题
	setColor(13);
	gotoXY(44,3);
	printf("游戏说明");

	//输出边框
	//控制行
	for (i = 6; i <= 22; i++)
	{
		//控制列
		for (j = 20; j <= 75; j++)
		{
			//上下边框
			if (i == 6 || i == 22)
			{
				gotoXY(j, i);
				printf("=");
			}
			//左右边框
			if (j == 20 || j == 75)
			{
				gotoXY(j, i);
				printf("|");
			}
			else
				printf(" ");//输出空格
		}
	}

	//输出菜单选项
	setColor(3);
	gotoXY(30, 8);
	printf("1.不能撞到墙,不能吃到自己");

	setColor(5);
	gotoXY(30, 11);
	printf("2.F1加速前进,F2减速前进");

	setColor(11);
	gotoXY(30, 14);
	printf("3.使用空格键暂停游戏或继续游戏");

	setColor(13);
	gotoXY(30, 17);
	printf("4.使用方向键控制前进的方向");

	setColor(14);
	gotoXY(30, 20);
	printf("5.按下ESC键退出游戏");

	setColor(12);
	gotoXY(20,24);
	printf("按下回车键回到主界面");
	getchar();//按下回车键继续

	return 0;
}

int printMap(void)
{
	int i = 0, j = 0;
	//清屏
	system("cls");

	//控制行
	for (i = 0; i <= 26; i++)
	{
		//控制列
		for (j = 0; j <= 56; j=j+2)
		{
			//控制光标
			gotoXY(j, i);
			if (0 == i || 26 == i || 0 == j || 56 == j)
			{
				setColor(13);
				printf("□");
			}
			else
			{
				setColor(3);
				printf("■");//■
			}
		}
	}

	//getchar();//按下回车键继续
	return 0;
}

//显示分数和提示信息
int showScoreTips(void)
{
	int highscore = 0;

	//从文件中读取最高分
	highscore = readFile();

	//显示最高分
	setColor(3);
	gotoXY(64, 4);
	printf("※※历史最高分※※:%d",highscore);

	//显示当前得分
	setColor(14);
	gotoXY(64, 8);
	printf("※※当前得分※※:%d",score);

	//显示温馨提示
	setColor(12);
	gotoXY(72, 11);
	printf("温馨提示");

	//绘制上下边框
	setColor(10);
	gotoXY(60, 13);
	printf("==============================");

	gotoXY(60, 25);
	printf("==============================");

	//输出温馨提示
	setColor(13);
	gotoXY(64, 14);
	printf("※ 吃掉每个食物得分:%d",add);

	gotoXY(64, 16);
	printf("※ 不能撞到墙壁,不能咬到自己");

	gotoXY(64, 18);
	printf("※ F1加速前进,F2减速前进");

	gotoXY(64, 20);
	printf("※ 按下空格暂停游戏或继续游戏");

	gotoXY(64, 22);
	printf("※ 使用←→↑↓控制前进的方向");

	gotoXY(64, 24);
	printf("※ 按下ESC退出游戏");

	//getchar();//按下回车键继续

	return 0;
}

//从save.txt文件中读取最高分
int readFile(void)
{
	int ret = -1;
	char buf[32];

	FILE* fp = NULL;

	//1以只读的方式打开文件夹
	fp = fopen("save.txt", "r");
	if (NULL == fp)
	{
		printf("fopen failed...\n");
		return 0;
	}
	//2读取文件内容
	memset(buf, 0, sizeof(buf));
	ret = fread(buf, sizeof(char), sizeof(buf), fp);
	if (ret <= 0)
	{
		printf("fread failed...\n");
		return 0;
	}
	//3关闭文件
	fclose(fp);

	//atoi-->将字符串数字转化为数字 “123”->123
	return atoi(buf);
}

//初始化蛇
int initSnake(void)
{
	//system("cls");
	int i = 0;

	snake_t * new = NULL;
	snake_t * tmp = NULL;

	//循环创造4个节点
	for (i = 0; i < 4; i++)
	{
		//分配空间
		new = malloc(sizeof(snake_t));
		if (NULL == new)
		{
			printf("malloc initSnake failed...\n");
			return -1;
		}
		memset(new, 0, sizeof(snake_t));

		//赋值
		new->x = 24 + i * 2;
		new->y = 5;

		//头插法
		new->next = head;
		head = new;
	}

	//遍历链表
	tmp = head;
	while (tmp != NULL)
	{
		//设置蛇的颜色 14 黄色
		setColor(14);
		//定位光标
		gotoXY(tmp->x, tmp->y);

		if (tmp == head)
		{
			printf("●"); //●
		}

		printf("★");//★

		tmp = tmp->next;
	}

	return 0;
}

//随机食物
int randFood(void)
{
	snake_t* tmp = NULL;

	//随机的食物不能出现在墙壁上
	//随机的食物不能出现在蛇身上
	//随机的食物x坐标一定是偶数

	//分配空间
	foodNode = malloc(sizeof(snake_t));
	if (NULL == foodNode)
	{
		gotoXY(1, 28);
		printf("malloc failed...");
		return -1;
	}
	memset(foodNode, 0, sizeof(snake_t));

	while (1)
	{
		while (1)
		{
			//保证X坐标是偶数 同时不应该出现在墙上   坐标应为:(2,54)
			foodNode->x = rand() % 53 + 2;

			if (0 == foodNode->x % 2)
				break;
		}

		//y的坐标是(1,25)
		foodNode->y = rand() % 25 + 1;

		//食物没有在蛇身上
		if (NULL == tmp)
		{
			gotoXY(foodNode->x, foodNode->y);
			setColor(12);
			printf("●");
			break;
		}
		else
		{
			continue;
		}
	}

	//getchar();//按下回车键继续
	return 0;
}

int moveSnake(void)
{
	snake_t* new = NULL;
	snake_t* tmp = NULL;
	snake_t* save = NULL;

	new = malloc(sizeof(snake_t));
	if (NULL == new)
	{
		printf("malloc failed...\n");
		return -1;
	}
	memset(new, 0, sizeof(snake_t));

	//向上移动
	if (UP == direction)
	{
		new->x = head->x;
		new->y = head->y - 1;
	}

	//向下移动
	if (DOWN == direction)
	{
		new->x = head->x;
		new->y = head->y + 1;
	}

	//向右移动
	if (RIGHT == direction)
	{
		new->x = head->x + 2;
		new->y = head->y;
	}

	//向左移动
	if (LEFT == direction)
	{
		new->x = head->x - 2;
		new->y = head->y;
	}

	new->next = head;
	head = new;

	tmp = head;
	setColor(14);

	//判断是否为食物
	if ((new->x == foodNode->x) && (new->y == foodNode->y))
	{
		//循环画出蛇
		while (NULL != tmp) {
			gotoXY(tmp->x, tmp->y);
			if (tmp == head)
				printf("●");
			else
				printf("★");

			tmp = tmp->next;
		}
		//吃掉一个食物 增加分数
		score = score + add;
		//再随机食物
		randFood();
	}
	else
	{
		while (NULL != tmp->next)
		{
			gotoXY(tmp->x, tmp->y);
			if (tmp == head)
				printf("●");
			else
				printf("★");

			save = tmp;
			tmp = tmp->next;
		}

		//将最后一个节点释放
		gotoXY(tmp->x, tmp->y);
		setColor(3);
		printf("■");

		save->next = NULL;
		free(tmp);
	}
	return 0;
}

int moveKeyControl(void)
{
	direction = RIGHT;

	while (1)
	{
		showScoreTips();

		//向上
		if (GetAsyncKeyState(VK_UP) && direction != DOWN)
		{
			direction = UP;
		}

		//向下
		if (GetAsyncKeyState(VK_DOWN) && direction != UP)
		{
			direction = DOWN;
		}

		//向左
		if (GetAsyncKeyState(VK_LEFT) && direction != RIGHT)//GetAsyncKeyState获取键盘输入信息
		{
			direction = LEFT;
		}

		//向右
		if (GetAsyncKeyState(VK_RIGHT) && direction != LEFT)
		{
			direction = RIGHT;
		}

		//按下空格键暂停游戏或继续游戏
		if (GetAsyncKeyState(VK_SPACE))
		{
			while (1)
			{
				Sleep(300);
				if (GetAsyncKeyState(VK_SPACE))
					break;
			}
		}

		//按下F1键加速
		if (GetAsyncKeyState(VK_F1))
		{
			//减少睡眠的时间 但睡眠时间不少于50ms
			speedUp();
		}

		//按下F2键加速
		if (GetAsyncKeyState(VK_F2))
		{
			//增加睡眠的时间 但睡眠时间不大于350ms
			speedDown();
		}

		//按下ESC键结束游戏
		if (GetAsyncKeyState(VK_ESCAPE))
		{
			//表示用户按下ESC键结束游戏
			endStatus = 3;
			endGame();
			//exit(1);
			break;
		}

		Sleep(sleepTime);

		moveSnake();

		//判断是否撞到墙
		if (isHitWall())
		{
			endStatus = 1;
			endGame();
			break;
		}

		//判断是否咬到自己
		if (isBitSelf())
		{
			endStatus = 2;
			endGame();
			break;
		}
	}

	getchar();
	return 0;
}

//加速蛇的移动
int speedUp(void)
{
	//最快的速度 睡眠时间50ms
	while (sleepTime > 50)
	{
		sleepTime = sleepTime - 20;
		add = add + 2;
	}

	return 0;
}

//减速蛇的移动
int speedDown(void)
{
	if (sleepTime < 350)
	{
		sleepTime = sleepTime + 20;
		//减少增加的分数
		add = add - 2;
	}

	if (add <= 0)
	{
		add = 1;
	}

	return 0;
}

//判断是否撞墙 撞墙返回1 否则返回0
int isHitWall()
{
	//表示撞到墙壁
	if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
	{
		return 1;
	}

	//表示没有撞到墙壁
	return 0;
}

//判断是否咬到自己 咬到自己返回1 否则返回0
int isBitSelf()
{
	snake_t* tmp = NULL;

	//从第二个节点开始算
	tmp = head->next;

	while (NULL != tmp)
	{
		if ((head->x == tmp->x) && (head->y == tmp->y))
		{
			return 1;
		}
		//指向下一个节点
		tmp = tmp->next;
	}

	return 0;
}

//游戏失败边框
void failGameUi()
{
	int i = 0;

	//清屏
	system("cls");

	//显示游戏失败提示
	setColor(12);
	gotoXY(44, 3);
	printf("游 戏 失 败!");

	//设置边框的颜色
	setColor(11);
	gotoXY(17, 5);

	//绘制上边框
	printf("+----------------------------------------------------------------+");
	//绘制下边框
	gotoXY(17, 20);
	printf("+----------------------------------------------------------------+");

	//绘制左右边框
	for(i = 6; i <= 19; i++)
	{
		gotoXY(17, i);
		printf("|");

		gotoXY(82, i);
		printf("|");
	}

}

//结束游戏
int endGame(void)
{
	int n;
	int highScore = 0;

	while (1)
	{
		//显示游戏失败界面
		failGameUi();

		setColor(12);
		gotoXY(38, 9);

		//不同的状态 显示不同的失败提示 endStatus
		switch (endStatus)
		{
			//撞到墙壁
		case 1:
			printf("您撞到墙壁了,游戏结束!");
			break;
			//咬到自己
		case 2:
			printf("您咬到蛇身了,游戏结束!");
			break;
			//按下ESC键
		case 3:
			printf("您已经结束了游戏,游戏结束!");
			break;
		default:
			break;
		}

		//显示您的得分
		setColor(13);
		gotoXY(43, 12);
		printf("您的得分:%d", score);

		//显示最高分
		//从文件中读取最高分
		highScore = readFile();

		if (score > highScore)
		{
			setColor(10);
			gotoXY(38, 16);
			printf("恭喜您,您已经破纪录了!");
			//将最高分写入文件
			writeFile(score);
		}
		else
		{
			setColor(10);
			gotoXY(38, 16);
			printf("加油哦,离最高分还差%d分", highScore - score);
		}

		//输出用户选择的信息
		gotoXY(25, 23);
		setColor(12);
		printf("再玩一局请输入:1");

		gotoXY(52, 23);
		printf("直接退出请输入:2");

		gotoXY(46, 25);
		setColor(11);
		printf("请选择:");

		scanf("%d", &n);
		getchar();

		if (n == 1)
		{
			score = 0;
			sleepTime = 350;
			add = 1;
			destorySnake();
			break;
		}
		else if(n==2)
		{
			exit(0);
		}
		else
		{
			setColor(12);
			gotoXY(30, 27);
			printf("您输入有误,请重新输入,按下回车继续...");
			getchar();
			//system("cls");
		}
	}

	return 0;
}

int writeFile(int score)
{
	FILE* fp = NULL;

	//打开文件
	fp = fopen("save.txt", "w+");
	if (NULL == fp)
	{
		printf("打开文件失败\n");
		return -1;
	}

	//将最高分写入文件中
	fprintf(fp, "%d", score);

	//关闭文件
	fclose(fp);

	return 0;
}

int destorySnake(void)
{
	snake_t* tmp = NULL;
	snake_t* save = NULL;

	tmp = head;
	while (NULL != tmp)
	{
		save = tmp->next;
		free(tmp);

		tmp = save;
	}

	head = NULL;

	return 0;
}
 

##功能介绍
欢迎界面——“开始游戏”“功能介绍”“退出游戏”
游戏体验——判断蛇是否撞到墙,是否咬到自身从而游戏失败;
可控制上下左右四个方向进行蛇的移动并控制蛇的移动速度;
可对分数进行存档并记录最高分;
##最后
希望小伙伴们可以亲自动手尝试一下,虽然过程中会遇到很多麻烦的bug,但是这是每个人通往成功的必经之路,所以,不要害怕,勇敢面对吧,你会收获满满的成就感~
同时,siren也把源码分享到博客https://xysiren.github.io/上面了,上面也有很多有趣的内容,欢迎大家观看~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值