这里是基于nucrses库的贪吃蛇
所以下面先解释下nucrses库中的一些函数:
- printw(): 就是printf函数 使用基本一样,不同的是:printw()函数把字符串输出到“stdscr”的虚拟窗口
- initscr():这个函数初始化了curses 系统并且为当前屏幕(也就是“stdscr”)和相关的数据结构分配内存。
- endwin():endwin()函数释放了curses 子系统和相关数据结构占用的内存,使你能够正常返回控制台模式。
- refresh():告诉curses系统将缓冲区的内容输出到屏幕上。
- noecho():从键盘获取值但不显示
- keypad(stdscr,TRUE):使用curses里的特殊方向键,第一个参数是WINDOW类型,这里我们前面提到了是stdscr,第二个是bool类型,TRUE是允许。
- getch():获取用户输入
蛇的结构体定义:
struct Snake
{
int x;
int y;
struct Snake *next;
}
头文件声明:
#include<curses.h>
#include <stdlib.h>
#include <pthread.h>
#include "snake.h"
#define MAP_LENGTH 20 //地图长
#define MAP_WIDETH 20//宽
extern struct Snake *g_snake;//定义蛇
struct Snake food;
int dir=KEY_RIGHT;//默认初始方向为右
int eat=0;//判断食物是否被吃到 0为没有,1为吃到
void initfood()//初始化食物
int Eat_food()//判断是否吃到食物
int init_Map()//初始化地图
void delete_snake(struct Snake *p)//蛇的滚动
int suicide()//咬到自己死
int Against_wall()//撞墙
void distory_snake()//若撞墙,初始化蛇的位置
int Determine_direction(int key)//判断方向
void handle_key()//按键控制
void snake_move()//蛇的移动
void add_snake(struct Snake **p,int x,int y)//增加蛇身
void Creat_snake()//创建蛇的初始位置
int find_snake(struct Snake *p,int x,int y)//在地图遍历寻找蛇身,找到返回0,找不到返回-1
实现思路:
这里我是用头插法实现蛇的变长:
void add_snake(struct Snake **p,int x,int y)//增加蛇身
{
struct Snake *snake_body=(struct Snake*)malloc(sizeof(struct Snake));
snake_body->x=x;
snake_body->y=y;
snake_body->next=NULL;
snake_body->next=*p;
*p=snake_body;
}
所以要让蛇滚动只需新添一个头节点,再删除尾节点:
void delete_snake(struct Snake *p)//蛇的滚动
{
struct Snake *tmp;
while(p!=NULL&&p->next!=NULL)
{
tmp=p->next;
if(tmp->next==NULL)
{
p->next=NULL;
free(tmp);
break;
}
p=p->next;
}
}
//然后只需新添一个头节点,再删除尾节点
add_snake(&g_snake,g_snake->x-1,g_snake->y);
delete_snake(g_snake);
吃食物呢,就是判断食物的点是否和蛇头重合,重合就新添一个点
int Eat_food()//判断是否吃到食物
{
if(g_snake->x==food.x&&g_snake->y==food.y)
{
return 0;
}
return 1;
}
撞墙呢,就是判断蛇头的点是否和地图边缘相等
int Against_wall()//撞墙
{
if(g_snake->x==0||g_snake->x==19||g_snake->y==0||g_snake->y==19)
{
return 0;
}
return -1;
}
最终代码实现:
main.c
#include<curses.h>
#include <stdlib.h>
#include <pthread.h>
#include "snake.h"
#define MAP_LENGTH 20
#define MAP_WIDETH 20
extern struct Snake *g_snake;//定义蛇
struct Snake food;
int dir=KEY_RIGHT;//默认初始方向为右
int eat=0;//判断食物是否被吃到 0为没有,1为吃到
void initfood()//初始化食物
{
int judge;
srand((int)time(0));
do
{
food.x=rand()%20+1;
food.y=rand()%20+1;
if(food.x==g_snake->x&&food.y==g_snake->y)
{
judge=1;
}
}while(food.x==0||food.x>18||food.y==0||food.y>18||judge==1);
}
int Eat_food()//判断是否吃到食物
{
if(g_snake->x==food.x&&g_snake->y==food.y)
{
return 0;
}
return 1;
}
int init_Map()//初始化地图
{
int i;
int j;
for(i=0;i<MAP_LENGTH;i++)
{
for(j=0;j<MAP_WIDETH;j++)
{
if(j==0||j==MAP_WIDETH-1)
{
if(j==0)
{
printw("| ");
}
else
{
printw(" |");
}
}
else
{
if(i==0||i==MAP_LENGTH-1)
{
printw("--");
}
else
{
if(find_snake(g_snake,i,j)==0)//显示蛇的位置
{
printw("[]");
}
else if(food.x==i&&food.y==j)
{
printw("$$");
}
else
{
printw(" ");
}
}
}
}
printw("\n");
}
}
void delete_snake(struct Snake *p)//蛇的滚动
{
struct Snake *tmp;
while(p!=NULL&&p->next!=NULL)
{
tmp=p->next;
if(tmp->next==NULL)
{
p->next=NULL;
free(tmp);
break;
}
p=p->next;
}
}
int suicide()//咬到自己死
{
struct Snake *head;
struct Snake *body;
head=g_snake;
body=g_snake->next;
while(body!=NULL)
{
if(head->x==body->x&&head->y==body->y)
{
return 0;
}
body=body->next;
}
return 1;
}
int Against_wall()//撞墙
{
if(g_snake->x==0||g_snake->x==19||g_snake->y==0||g_snake->y==19)
{
return 0;
}
return -1;
}
void distory_snake()//初始化蛇的位置
{
struct Snake *p;
while(g_snake!=NULL)
{
p=g_snake;
g_snake=g_snake->next;
free(p);
}
}
// 获取当前移动方向
// 判断是否跟上一次方向dir相反
// return;
//更新dir为当前方向
int Determine_direction(int key)//判断方向
{
//判断按键是否为方向键
if (key==KEY_UP||key==KEY_DOWN||key==KEY_LEFT||key==KEY_RIGHT)
{
//判断当前方向与之前是否相反
if((dir==KEY_UP&&key==KEY_DOWN)||(dir==KEY_DOWN&&key==KEY_UP)||(dir==KEY_LEFT&&key==KEY_RIGHT)||(dir==KEY_RIGHT&&key==KEY_LEFT))
{
return 0;
}
}
dir=key;
return -1;
}
void handle_key()//按键控制
{
int key;
noecho();//从键盘获取值但不显示
keypad(stdscr,TRUE);//使用curses里的特殊方向键,一般以KEY开头
struct Snake *node=(struct Snake*)malloc(sizeof(struct Snake));
while(1)
{
key=getch();
if(Determine_direction(key)==0)
{
continue;
}
}
}
void snake_move()//蛇的移动
{
while(1)
{
clear();
switch(dir)
{
case KEY_UP:
if(Eat_food()==0)
{
add_snake(&g_snake,g_snake->x-1,g_snake->y);
eat=1;
}
else
{
add_snake(&g_snake,g_snake->x-1,g_snake->y);
delete_snake(g_snake);
}
break;
case KEY_DOWN:
if(Eat_food()==0)
{
add_snake(&g_snake,g_snake->x+1,g_snake->y);
eat=1;
}
else
{
add_snake(&g_snake,g_snake->x+1,g_snake->y);
delete_snake(g_snake);
}
break;
case KEY_LEFT:
if(Eat_food()==0)
{
add_snake(&g_snake,g_snake->x,g_snake->y-1);
eat=1;
}
else
{
add_snake(&g_snake,g_snake->x,g_snake->y-1);
delete_snake(g_snake);
}
break;
case KEY_RIGHT:
if(Eat_food()==0)
{
add_snake(&g_snake,g_snake->x,g_snake->y+1);
eat=1;
}
else
{
add_snake(&g_snake,g_snake->x,g_snake->y+1);
delete_snake(g_snake);
}
break;
default:
break;
}
if(Against_wall()==0||suicide()==0)
{
distory_snake();
Creat_snake();
}
if(eat==1)
{
initfood();
eat=0;
}
init_Map();
refresh();
usleep(200000);
}
}
int main()
{
pthread_t _t_snake_move;//线程1:蛇的移动
pthread_t _t_handle_key;//线程2:方向判断
initscr();
Creat_snake();
initfood();
init_Map();
pthread_create(&_t_snake_move,NULL,(void *)snake_move,NULL);
pthread_create(&_t_handle_key,NULL,(void *)handle_key,NULL);
while(1);
endwin();
return 0;
}
snake.c(链表处理大部分在这里面所以我分出来了)
#include<curses.h>
#include <stdlib.h>
#include "snake.h"
struct Snake *g_snake=NULL;
void add_snake(struct Snake **p,int x,int y)//增加蛇身
{
struct Snake *snake_body=(struct Snake*)malloc(sizeof(struct Snake));
snake_body->x=x;
snake_body->y=y;
snake_body->next=NULL;
snake_body->next=*p;
*p=snake_body;
}
void Creat_snake()//创建蛇的初始位置
{
g_snake=(struct Snake*)malloc(sizeof(struct Snake));
g_snake->x=2;
g_snake->y=3;
g_snake->next=NULL;
add_snake(&g_snake,2,4);
add_snake(&g_snake,2,5);
}
//在地图遍历寻找蛇身,找到返回0,找不到返回-1
int find_snake(struct Snake *p,int x,int y)
{
while(p!=NULL)
{
if(p->x==x&&p->y==y)
{
return 0;
}
p=p->next;
}
return -1;
}
snake.h
#ifndef SNAKE_H
#define SNAKE_H
struct Snake
{
//蛇身对应坐标
int x;
int y;
struct Snake* next;
};
int find_snake(struct Snake* p, int x, int y);//在地图遍历寻找蛇身,找到返回0,找不到返回-1
void Creat_snake();//创建蛇的初始位置
void add_snake(struct Snake** p, int x, int y);//增加蛇身
void handle_key();//按键控制
int init_Map();//初始化地图
#endif