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 实现贪吃蛇完整代码