C语言_综合项目——贪吃蛇

综合项目——贪吃蛇

1. 程序分析

通过控制蛇头方向吃食物,使得蛇变长,从而获得积分。通过上下左右键控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬到自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。
1.1 模块设计
在本游戏中,从键盘输入来获取移动方向和蛇的移动关系
贪吃蛇:
M(模型)
蛇模块:蛇的初始化、蛇的移动、蛇长度改变、蛇的死亡
随机数生成模块:获取随机数(与食物一起)
食物模块:食物的产生、食物的消失
V(视图)
界面处理模块:加载地图、预处理地图、渲染地图
C(控制器)
游戏控制模块:控制键盘输入、执行游戏流程
记录蛇的坐标位置信息等
C语言_综合项目——贪吃蛇_第1张图片
1.2 模块描述
蛇的初始化(定义结构体 x、y坐标)
蛇的初始化实际就是二维数组的初始化,该二维数组存储两个值,里面包含该蛇身体的坐标信息,它出现的初始位置是横纵坐标的中间位置。
蛇的移动
蛇的移动是通过改变二维数组坐标位置来实现的,例如当蛇向前进一个单位,则将尾每一个身体位置的坐标改变,同时改变蛇头、蛇身以及蛇尾的方向。这样整体看来蛇就前进了一个单位。
蛇的增长
当蛇吃了正常食物后,蛇的长度会增加,增加蛇的长度就是在食物的位置增加一个二维数组并且将这个位置变为蛇头。
蛇的死亡
当蛇撞上障碍物、自身或者通关时,蛇会死亡,蛇死亡就是二维数组的销毁。
食物的产生
食物出现的位置产生都是随机的,这些因素由通过随机函数获取的随机数决定。食物的位置不能出现在障碍物和边界上。
控制键盘输入
通过获取键盘输入的W/w(上)、S/s(下)、A/a(左)、D/d(右)来改变蛇模块中移动方向,从而影响蛇的移动方向。

1.3 项目分析
游戏界面显示之后,会根据读取的移动方向来控制蛇的移动,蛇移动之后会吃食物,食物被吃掉之后又会随机生成,然后刷新界面,将界面显示出来。
刷新界面时会判断蛇的状态,如果蛇死亡,则游戏结束;如果蛇胜利晋级则进入下一关,重新加载地图,显示新的一关的游戏初始界面;如果蛇没有死亡也没有晋级过关,继续本关游戏,则按照读取的键盘输入控制蛇的移动。

2. 项目实现

2.1 项目创建
蛇的结构
用来存放蛇的长度和位置坐标
蛇移动函数
用来实现游戏的控制和判断
显示游戏界面函数
用来实现游戏的显示
主函数
用来实现游戏流程控制

2.2 项目设计
Snake.c:

#include
#include
#include
#include
#include
#include  
#include
#include"Snake.h"
/*
	1.定义蛇的结构体
	2.初始化蛇和食物
	3.开始游戏
		蛇和墙的碰撞
		蛇和自身碰撞
		蛇和食物碰撞
			重新随机食物
			蛇身体增长
			分数增长
		方向键控制
	4.游戏结束
*/
//获取食物随机数 
//习惯性把函数放在主函数上面,在Snake.h中声明了所以放哪都行
void InitFood()
{
     
	//srand((size_t)time(NULL));//这句话使用多次放到主函数中,不需要多次加入随机数种子
	food[0]=rand()%WIDE;
	food[0]=rand()%HIGH;	
}
//获取蛇随机数
void InitSnake()
{
     
	snake.size=2;
	snake.body[0].X=WIDE/2;
	snake.body[0].Y=HIGH/2;
	snake.body[1].X=WIDE/2-1;
	snake.body[1].Y=HIGH/2;
	
}
//显示蛇的位置 显示食物位置
void ShowUI()
{
     
	COORD coord;
	//更新蛇末尾空格
	coord.X=lx;
	coord.Y=ly;
	SetConsoleCursorPosition(GetStdHandle(std_OUTPUT_HANDLE),coord);
	putchar(' ');
	
	//显示蛇的位置
	for(int i=0;i<snake.size;i++)
	{
     
		coord.X=snake.body[i].X;//蛇第几节身体的X坐标
		coord.Y=snake.body[i].Y;
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
		if(i==0)//蛇头
		{
     
			putchar('@');
		}
		else
		{
     
			putchar('*');
		}
	}
	//显示食物的位置
	coord.X=food[0];
	coord.Y=food[0];
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
	putchar('#');
}
//玩游戏
void PlayGame()
{
     
	char key='D';
	//玩游戏 蛇和墙的碰撞 四个约束
	while(sbake.body[0].X>=0 && snake.body[0].X<WIDE && snake.body[0].Y>=0 && snake.body[0].X<HIGH)
	{
     
		//加载墙
		//InitWall();
		//显示界面值
		ShowUI();
		//方向控制
		while(_kbhit())
		{
     
			key=_getch();
			//默认key='D',若输入为'A'不执行
		}
		switch(key)
		{
     
			case 'D':case 'd':dx=1,dy=0;break;//右
			case 'A':case 'a':dx=-1,dy=0;break;//左
			case 'W':case 'w':dx=0,dy=-1;break;//上
			case 's':case 'S':dx=0,dy=1;break;//下
		}
		//蛇和自身碰撞
		for(int i=1;i<snake.size;i++)//蛇头和下面的身子碰撞
		{
     
			if(snake.body[0].X==snake.body[i].X && snake.body[0].Y==snake.body[i].Y)
			{
     
				return ;	
			}
		}
		//蛇和食物碰撞
		if(snake.body[0].X==food[0] && snake.body[0].Y==food[1])
		{
     
			
			//随机新食物
			InitFood();
			//蛇身体增长
			snake.size++;
			//分数增长
			score+=10;
			//关卡 速度 障碍物	
		}
		//蛇更新坐标
			//记录蛇尾坐标
		lx=snake.body[snake.size-1].X;
		ly=snake.body[snake.size-1].Y;
		
		for(int i=snake.size=1;i>0;i--)//倒着赋值
		{
     
			//更新蛇身体坐标
			snake.body[i].X=snake.body[i-1].X;
			snake.body[i].Y=snake.body[i-1].Y;
		}
		//更新蛇头坐标
		snake.body[0].X+=dx;
		snake.body[i].Y+=dy;
		sleep(1000);
		//system("cls");
		//不加这句话蛇在没迟到食物之前,尾巴边长
		//清空上一次屏幕内容重新绘制,更新动画帧,每次清屏会使得每次都加载墙闪烁
	}
}
//初始化墙信息
void InitWall()
{
     
	for(int i=0;i<=WIDE;i++)
	{
     
		for(int j=0;j<=HIGH;i++)//选中 shifr+u high-->HIGH
		{
     
			if(i==WIDE)
				putchar('=');
			else if(j=HIGH)
				putchar('=');
			else
				putchar(' ');
		}
		putchar('\n');
	}
}
int main()
{
     
	srand((size_t)time(NULL));
	
	//去掉控制台光标 蛇身后面的小横杠
	CONCLE_CURSOR_INFO cci;//控制台光标结构体
	cci.dwSize=sizeof(cci);//实际大小
	cci.bVisible=FALSE;//可视
	SetConsoleCursorInfo(GetStdHanle(STD_OUTPUT_HANDLE),&cci);
	
	InitWall();
	InitFood();
	InitSnake();
	PlayGame();
	//ShowUI();
	
	/*
	//显示蛇头的位置
	COORD coord;//COORD结构体名称 coord结构体变量名
	coord.X=food[0];
	coord.Y=food[0];
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);//把coord结构体放在这
	printf("@");
	printf("%d %d",food[0],food[1]);
	*/
	/*
	//测试显示的框多大
	for(int i=0;i<30;i++)
	{
		for(int i=0;i<60;i++)
		{
			printf("*");
		}
		printf("\n");
	}
	*/
	return 0;
}

Snake.h:

#pragma once

#define WIDE 60
#define HIGH 20

struct BODY
{
     
	int X;
	int Y;
};
struct SNAKE
{
     
	int size;
	struct BODY body[WIDE*HIGH];
}snake;//结构体变量名(全局变量名)
//typedef struct SNAKE
//{
     
//	int size;
//	struct BODY body[WIDE*HIGH];
//}snake;//结构体别名

int food[2]={
     0};//food[0]为X坐标 food[1]为Y坐标 
int score=0;//得分

int dx=0;//偏移坐标
int dy=0;

//墙每次不需要再PlayGame里刷新,在main里初始化,记录蛇尾最开始的位置,蛇移动的时候把蛇尾打印成空格
//记录蛇末尾坐标
int lx=0;
int ly=0;

void InitFood();//获取食物随机数 
void InitSnake();//获取蛇随机数 
void ShowUI();//显示蛇的位置 显示食物位置
void PlayGame();//玩游戏
void InitWall();//初始化墙信息

设置控制台(cmd)光标位置 Win32系统编程函数: 用来控制蛇的位置
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);
需要导入的头文件:#include
COORD是Windows API中定义的一种结构,表示一个字符在控制台屏幕上的坐标。
COORD为系统定义的结构体:
C语言_综合项目——贪吃蛇_第2张图片
void PlayGame();//玩游戏 蛇和墙的碰撞 四个约束
C语言_综合项目——贪吃蛇_第3张图片
蛇身体增长 更新坐标:蛇身子延着蛇头走,蛇头横/纵左边不变,另一个往前走1,蛇身后面一个的坐标=前一个坐标
C语言_综合项目——贪吃蛇_第4张图片
getch() (VC++6.0下为_getch())
功能:从控制台无回显地取一个字符
无回显:输入字符在屏幕上不显示但还能接收(输入密码)
用法:int _getch(void)
返回值:读取的字符
包含都闻见:#include

kbhit() (VC++6.0下为_kbhit())
功能及返回值:检查当前是否有键盘输入,若有则返回一个非0值,否则返回0
用法:int kbhit(void);
包含头文件:#include

你可能感兴趣的:(C语言)