基于linux ncurses的C语言贪吃蛇

C语言实现贪吃蛇

对于ncurses库起初完全不熟悉,不知道有那些函数可以调用,在文章的开头先总结一下项目实现过程用到过的函数
  • initscr()······· 初始化屏幕
  • raw() ······· 设置使所有的输入不需要输入回车就可以传递给程序
  • noecho() ······· 设置不回显用户输入内容
  • curs_set(0) ······· 关闭光标显示
  • keypad(stdscr, 1)······· 允许用户终端的键盘,允许getch()函数获取功能键
  • nodelay(stdscr, 1) ······· 多线程并发输入,使程序不用一直在getch()等待用户输入
  • refresh() ······· 刷新屏幕,将字符打印屏幕刷新显示
  • endwin()······· 结束ncurse屏幕绘画
  • printw() ······· 格式化输出,相当于printf
  • mvprintw ······· 在指定位置格式化输出,前两个参数为屏幕坐标想x, y

首先定义了蛇的特征,蛇的坐标等结构体,在结构体中包括了蛇的头,蛇的长度,完成时使用到了链表,所以保存了蛇的头,也就可以遍历整条蛇

/*snake coordinate including x,y*/
typedef struct snake_coordinate{
	int x;
	int y;
}SNAKE;

/*snake body coordinate struct, to load the snake*/
typedef struct snake_load{
	SNAKE coordinate;
	struct snake_load *next;
}SNAKE_LOAD;

/*snake features including snake_head, and it's length*/
typedef struct snake_features{
	SNAKE_LOAD *head;
	int length;
}SNAKE_CREAT;

下面是绘制地图的代码,地图格式为x(竖):22;y(横):25的大小,因为在linux的终端下横竖的间隔大小不一样,所以在横向上采用两个字符大小的显示空间来显示一个点

/*to print the game map*/
void map()

{
	for(int i = 0; i < 22; i++)
	{
		for(int j = 0; j < 50; j=j+2)
		{
			mvprintw(i, j, "*");
		}
	}
	for(int i = 1; i < 21; i++)
	{
		for(int j = 2; j < 48; j=j+2)
		{
			mvprintw(i, j, " ");
		}
	}
	
}

下面是蛇的打印,过程比较简单,这里就不主要叙述,直接上代码

void Creat_snake(int length)

{
	int located_x = 12;
	int located_y = 30;
	SNAKE snake;
	snake_wx.length = length;
	SNAKE_LOAD *snake_head_body = (SNAKE_LOAD*)malloc(sizeof(SNAKE_LOAD));
	snake_wx.head = snake_head_body;
	for(int i = 0; i < snake_wx.length; i++)
	{
		snake.x = located_x;
		snake.y = located_y;
		located_x++;
		SNAKE_LOAD *snake_body = (SNAKE_LOAD*)malloc(sizeof(SNAKE_LOAD));
		snake_head_body->coordinate = snake;
		snake_head_body->next = snake_body;
		snake_head_body = snake_body;
	}
	Print_snake();
}

我们将重点放在最令人头疼的地方,就是创建食物,食物的创建十分讲究,因为它的坐标不能落在蛇身上,也不能落在墙上,后者比较简单,前者难的原因主要在,食物的坐标是通过随机数产生的,产生一次后若刚好在蛇身上,得继续生成一个不在蛇的身上的,起初用到的方法最简单,但也是最难的,哭了,即是一个循环,让它不断产生直到满足条件,这里出现的问题是蛇在移动过程会出现卡顿现象,所以后来修改了另一种方法,第二种方法是如果不满足就继续调用食物创建函数直到满足条件,类似递归,这样做的问题在于会产生段错误,就是在调用rand的时候产生,至今未弄明白是为什么,最后采用了下面这种方法,即如果创建后在蛇身上,即进行加减运算处理,来满足条件,我也不知道还有没有其他的方法,希望有懂的小伙伴一起讨论。

void Creat_food()

{
	int flag = 1;
	SNAKE_LOAD *snake_head = snake_wx.head;
	srand((unsigned int)time(NULL));
	snake_food.x = rand() % 19;
	snake_food.y = rand() % 23;
	snake_food.y = snake_food.y * 2;
	while(1)
	{
		if(snake_food.x < 1 || snake_food.y < 2)
		{
			if(snake_food.x <= 1)
			{
				snake_food.x = snake_food.x + 2;
			}
			if(snake_food.y <= 2)
			{
				snake_food.y = snake_food.y * 2;
				if(snake_food.y == 0)
				{
					snake_food.y = snake_food.y + 2;
				}
			}
		}
		snake_head = snake_wx.head;
		for(int i = 0; i < snake_wx.length; i++)
		{
			if(snake_food.x == snake_head->coordinate.x && snake_food.y == snake_head->coordinate.y)
			{
				flag = 0;
				break;
			}
			snake_head = snake_head->next;
		}
		if(flag == 1)
		{
			break;
		}
		else
		{
			if(key == 260 || key == 261)
			{
				if(snake_food.x < 19 && snake_food.x > 5)
				{
					snake_food.x = snake_food.x - 2;
				}
				if(snake_food.x < 5)
				{
					snake_food.x = snake_food.x + 4;
				}
			}
			if(key == 259 || key == 258)
			{
				if(snake_food.y/2 < 23 && snake_food.y/2 > 5)
				{
					snake_food.y = (snake_food.y/2 - 4) * 2;
				}
				if(snake_food.y/2 < 5)
				{
					snake_food.y = (snake_food.y/2 + 4) * 2;
				}
			}
			flag = 1;
		}
	}
	mvprintw(snake_food.x, snake_food.y, "O");
}

最后还有一个重点的地方就是主函数的getch()获取用户输入,这个函数是会构成等待结果,所以要用nodelay这个函数让它不等待,才可以实现蛇的一直移动

/*Main*/
while((key = getch())){
		if(key > 0)  /*keydown*/
		{
			if(key == 258 && last_key == 259){
				key = 259;
			}
			if(key == 259 && last_key == 258){
				key = 258;
			}
			if(key == 260 && last_key == 261){
				key = 261;
			}
			if(key == 261 && last_key == 260){
				key = 260;
			}
			last_key = key;
		}
		else	   /*Don't keydown*/
		{
			key = last_key;
		}
		switch(key){
			case 258: //printw("down\n");
				  down();
				  break;
			case 259: //printw("up\n");
				  up();
				  break;
			case 260: //printw("left\n");
				  left();
				  break;
			case 261: //printw("right\n");
				  right();
				  break;
		}
		if(key == 3){
			break;
		}
		if(snake_wx.head->coordinate.x == 0 || snake_wx.head->coordinate.y == 0 || snake_wx.head->coordinate.x == 21 || snake_wx.head->coordinate.y == 48){
			break;
		}
		if(snake_wx.head->coordinate.x == snake_food.x && snake_wx.head->coordinate.y == snake_food.y){
			Creat_food();
			Eat_food();
		}
		refresh();
		usleep(120000);
	}

本文到这里结束,其他的实现代码比较普通所以不再讲述,完整代码放在了另一个帖子,有需要的小伙伴可以跳转获取,下面是链接
linux ncurses 实现贪吃蛇完整代码

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值