为了敲键盘及时响应,需要用到ncurse
ncurse上下左右键的获取
vi /usr/include/curses.h进入curses.h头文件,输入KEY_UP进入以下界面
这些称为curses的功能键,使用keypad可以在stdscr中接受键盘的功能键。
#include <curses.h>
int main()
{
//char c;//char 1 byte 8 bit 128 change to int
int key;
initscr();
keypad(stdscr,1);
while(1){
key = getch();
switch(key){
case KEY_DOWN:
printw("DOWN\n");
break;
case KEY_UP:
printw("UP\n");
break;
case KEY_LEFT:
printw("LEFT\n");
break;
case KEY_RIGHT:
printw("RIGHT\n");
break;
}
}
endwin();
return 0;
}
地图规划
void gamePic()
{
int row;
int line;
for(row=0;row<20;row++){
if(row==0){
for(line=0;line<20;line++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(line=0;line<=20;line++){
if(line==0 || line==20){
printw("|");
}else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(line=0;line<20;line++){
printw("--");
}
printw("\n");
}
}
printw("by Andy");
}
全部代码
#include <curses.h>
#include <stdlib.h>
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
struct Snake
{
int row;
int line;
struct Snake* next;
};
struct Snake* head = NULL;
struct Snake* tail = NULL;
int key;
int dir;
struct Snake food;
void initFood()//初始化食物节点
{
int x = rand() % 20;//随机出现位置
int y = rand() % 20;
food.row = x;
food.line = y;
}
void initNcurse()//初始化curses图形库
{
initscr();
keypad(stdscr,1);//使用keypad可以在stdscr中接受键盘的功能键
noecho();//对于输出的功能键的值不做出回应,以免界面溢出
}
int hasSnakeNode(int i,int j)//传参:行号,列号
{
struct Snake* p;
p = head;
while(p != NULL){
if(p->row==i && p->line==j){
return 1;//gamePic中打印一个节点"[]"
}
p=p->next;
}
return 0;
}
int hasFood(int i,int j)//打印食物
{
if(food.row==i && food.line==j){
return 1;
}
return 0;
}
void gamePic()//打印图形界面
{
int row;
int line;
move(0,0);
for(row=0;row<20;row++){
//第0行为20个"--"
if(row==0){
for(line=0;line<20;line++){
printw("--");
}
printw("\n");
}
//第0-19行为左右两边一个"|",中间21个" "(空格)为了对齐第一行
if(row>=0 && row<=19){//一共打印20行
for(line=0;line<=20;line++){
if(line==0 || line==20){
printw("|");//打印两边
}else if(hasSnakeNode(row,line)){
printw("[]");//打印蛇的身体
}else if(hasFood(row,line)){
printw("##");//打印食物
}
else{
printw(" ");//打印中间
}
}
printw("\n");
}
//打印第19行,与第一行一样
if(row==19){
for(line=0;line<20;line++){
printw("--");
}
printw("\n");
printw("by Andy,key = %d\n",key);//打印作者名字以及方向键的值
}
}
}
void addNode()//加节点
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新节点空间
new->next = NULL;
switch(dir){//根据用户按的功能键的方向来决定如何添加一个节点
case UP://列不变,行减一的位置添加
new->row = tail->row - 1;
new->line = tail->line;
break;
case DOWN:
new->row = tail->row + 1;
new->line = tail->line;
break;
case LEFT:
new->row = tail->row;
new->line = tail->line - 1;
break;
case RIGHT:
new->row = tail->row;
new->line = tail->line + 1;
break;
}
tail->next = new;
tail = new;//新节点变成尾部
}
void deleteNode()//删除节点
{
struct Snake* p;
p = head;
head = head->next;
free(p);
}
void initSnake()//初始化蛇的身体
{
struct Snake* p;//使用链表
dir = RIGHT;//初始化方向为右
while(head != NULL){
p = head;
head = head->next;
free(p);//遍历节点,释放空节点内存
}
initFood();//初始化食物
head = (struct Snake*)malloc(sizeof(struct Snake));//为头节点开辟空间
head->row = 1;//第一行
head->line = 1;//第一列
head->next = NULL;//防止野指针
tail = head;//头插法
addNode();//加4个节点
addNode();
addNode();
addNode();
}
int ifSnakeDie()//蛇死亡的条件
{
struct Snake* p;
p = head;
if(tail->row < 0 || tail->line == 0 || tail->row == 20 || tail->line == 20){//四个边界
return 1;
}
while(p->next != NULL){
if(p->row == tail->row && p->line == tail->line){//头咬到尾巴
return 1;
}
p = p->next;
}
return 0;
}
void moveSnake()//蛇的移动
{
addNode();
if(hasFood(tail->row,tail->line)){
initFood();
}
else{
deleteNode();
}
if(ifSnakeDie()){
initSnake();
}
}
void* refreshBox()//刷新界面
{
while(1){
moveSnake();//蛇移动
gamePic();//重新打印界面
refresh();//刷新覆盖原界面
usleep(100000);//0.1s
}
}
void turn(int direction)//绝对值解决方向问题
{
if(abs(dir) != abs(direction)){
dir = direction;
}
}
void* changeDir()//根据用户按的功能键走位
{
while(1){
key = getch();
switch(key){
case KEY_DOWN:
turn(DOWN);//转向
break;
case KEY_UP:
turn(UP);
break;
case KEY_LEFT:
turn(LEFT);
break;
case KEY_RIGHT:
turn(RIGHT);
break;
}
}
}
int main()
{
initNcurse();//第一步:搭建curses环境
initSnake();//第三步:打印蛇的身体
gamePic();//第二步:打印图形界面
pthread_t th1;//线程1
pthread_t th2;//线程2
pthread_create(&th1,NULL,refreshBox,NULL);//运行线程1:不断刷新界面
pthread_create(&th2,NULL,changeDir,NULL);//运行线程2:不断改变方向
while(1);//让线程一直进行
getch();//让程序一直重复输入功能键还能执行
endwin();//curses函数
return 0;
}
当然还可以有其他改进......