小小项目4:贪吃蛇

最近好久没有写博客了,主要忙于网络编程的学习和聊天室项目的编写,怕忘了这个好习惯,只能拿点以前的东西了
/**********************************************
time : 2017年8月10日16:04:59
filename: snack_1.c
maker: Leo
explain:little sncak game
***********************************************/

//要制作一个贪吃神游戏,首先我必须要有蛇,墙和食物。老师的看不懂。不管了,先敲一遍

//gcc snake_1.c -lpthread
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>

#define KEYCODE_U 0x41 //向上移动
#define KEYCODE_D 0x42 //向下移动
#define KEYCODE_L 0x44 //向左移动
#define KEYCODE_R 0x43 //向右移动

int kfd = 0;
struct termios cooked,raw;
char dir = KEYCODE_U;  //默认向上移动

//获取键盘响应:上下左右键
void* get_dir(void *a)
{
	while(1)
	{
		char c;
		tcgetattr(kfd,&cooked);  //得到termios结构体保存,然后重新配置终端
		//memcpy内存拷贝函数
		memcpy(&raw, &cooked,sizeof(struct termios));
		raw.c_lflag &=~ (ICANON | ECHO);
		raw.c_cc[VEOL] = 1;
		raw.c_cc[VEOF] = 2;
		tcsetattr(kfd, TCSANOW, &raw);
		
		//读取失败
		if(read(kfd, &c,1)<0) 
		{
			perror("read");
			exit(-1);   //表示非正常关闭
		}
		tcsetattr(kfd,TCSANOW,&cooked); //程序结束时在恢复原来的配置
		dir = c;
	}
}

unsigned char map[17][17] = {0};   //游戏地图
unsigned char snake[50] = {133};   //初始化蛇坐标,游戏开始的时候在(8,5)这个位置
unsigned char food = 67;     //食物的长度,游戏开始的时候在(4,3)的位置
int len = 1;                //保存蛇当前的长度

//将数字转化为坐标
void num_to_xy(unsigned char num,unsigned char *x,unsigned char *y)
{
	*x = num>>4;    //右移了四位,及用一个字节的四位地址保存x
	*y = (unsigned char)(num<<4) >> 4;    //清空四位地址值,及用四位高地质保存y
}     //因为需要改变x,y的值,所以用指针

//更新地图数据
void update_map()
{
	int i,j;
	
	//初始化地图
	for(i=0;i<17;i++)
	{
		for(j=0;j<17;j++)
		{
			if(i == 0 || i == 16 || j == 0 || j==16)  //设置边界
			{
				map[i][j] = '#';
			}
			else
			{
				map[i][j] = ' ';
			}
		}
	}
	
	//初始化食物
	unsigned char x,y;
	num_to_xy(food,&x,&y);  //获取食物坐标(4,3) 0100 0011 及67
	map[y][x] = '!';
	
	//初始化蛇
	for(i=0;i<len;i++)
	{
		num_to_xy(snake[i],&x,&y);   //获取蛇第i+1节身体的坐标
		map[y][x] = '*';   //表示蛇的身体  一维数组表示竖轴,二维数组表示横轴		
	}
	
}

//打印地图
void print_map()
{
	int i,j;
	for(i=0;i<17;i++)
	{
		for(j=0;j<17;j++)
		{
			printf("%c",map[i][j]);
		}
		printf("\n");
	}
	usleep(500*1000);    //0.1秒刷新
	//sleep(1);
	system("clear");     //清屏
}

//生成食物
unsigned char generate_food()
{
	//需要用到随机数
	srand((unsigned int)time(NULL));
	unsigned char new_food;
	unsigned char x,y;
	int insnake = 0;   //标志生成的食物没有在蛇的身体里,默认是不在
	do
	{
		insnake = 0;
		new_food = rand()%256;    //随机刷星一个食物
		num_to_xy(new_food,&x,&y);
		
		int i;
		for(i=0;i<len;i++)
		{
			if(snake[i] == new_food)
			{
				insnake = 1;   //代表
				break;
			}
		}
	}while(x==0 || x== 16 || y==0 || y==16 || insnake);
	
	return new_food;
}

//移动蛇
void move_snake()
{
	unsigned char x,y;    //坐标
	num_to_xy(snake[0], &x, &y);   //获取蛇头坐标
	
	//判断移动方向
	switch (dir)
	{
		case KEYCODE_U:
			y--;
			break;
		case KEYCODE_D:
			y++;
			break;
		case KEYCODE_L:
			x--;
			break;
		case KEYCODE_R:
			x++;
			break;
	}
	unsigned char last = snake[0];   //保存蛇头的位置
	snake[0] = (unsigned char)(x << 4) + y;  //更新蛇的位置
		
	int i;
	//移动蛇的身体
	unsigned char current;
	for(i=1;i<len;i++) //循环交换做到蛇的整体移动
	{
		current = snake[i];
		snake[i] = last;
		last = current;
	}
	
	//如果蛇头和食物重合,证明吃到食物
	//len是蛇的长度 为了满足数组,从零开始
	if(snake[0] == food)
	{
		//蛇要长一节
		snake[len] = last;
		len++;
		
		//重新生成食物
		food = generate_food();
	}
}

//判断蛇是否存活,如果返回值是0代表存活,1代表不应该存活啊
int isalive()
{
	unsigned char x,y;
	num_to_xy (snake[0],&x,&y);  //获取舌头
	
	//判断蛇头有没有越过边界
	if(x==0 || x== 16 || y==0 || y==16)
	{
		return 1;
	}
	
	//判断蛇头有没有咬到自己
	int i;
	for(i=1;i<len;i++)
	{
		//if(snake[0] = snake[i]);
		if(snake[0] == snake[i])
		{
			return 1;
		}
	}
	
	return 0;
}

int main()
{
	//开启一个线程用于获取键盘的上下左右键响应
	pthread_t tid1;
	pthread_create(&tid1,NULL,get_dir,NULL);
	while(1)
	{
		//更新数据地图
		update_map();
		
		//打印地图
		print_map();
		
		//移动蛇
		move_snake();
		
		if(isalive() == 1)
			break;
	}
	tcsetattr(kfd,TCSANOW,&cooked);  //程序结束是恢复原来的配置
	
	printf("Game Over.\n");
	return 0;
}



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值