提醒
要看明白此代码的萌新,你需要对结构体,指针有比较多的了解,并且需要了解Linux线程,此代码可以很好的练习结构体,指针,后续会更新我学C语言的一些基础总结,linux的学习,在编辑中
首先,我们要了解ncurse函数,我们知道贪吃蛇肯定要使用键盘的按键进行方向控制,常规的输入输出函数是实现不了的。ncurse可以响应键盘的方向键,在此库中定义了
#define KEY_DOWN 0402
#define KEY_UP 0403
#define KEY_LEFT 0404
#define KEY_RIGHT 0405
线程创建pthread_create(&th,NULL,func1,NULL)//需要包含头文件#include <pthread.h>
认识函数:int keypad(WINDOW *win, bool bf);其中,win
是一个指向 WINDOW
结构的指针,表示一个 ncurses 窗口对象,bf
是一个布尔值,用于指定是否启用键盘特殊键捕捉(true
表示启用,false
表示禁用。也可以用1或者0代替)
如果缺少 ncurses 库: 请确保您的系统上安装了 ncurses 库。您可以使用以下命令安装:
sudo apt-get update sudo apt-get install libncurses5-dev libncursesw5-dev
缺少 ncurses 库: 请确保您的系统上安装了 ncurses 库。您可以使用以下命令安装:
sudo apt-get update sudo apt-get install libncurses5-dev libncursesw5-dev
在运行时应该是这样先告诉编译器gcc snake.c -o snake -lncurses你使用了 ncurses 库
然后编译gcc snake.c -lncurses ,再运行
第一阶段先从按键获取开始
#include <ncurses.h>
int main()
{
int key;
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
while(1)
{
key = getch();//获取用户输入
switch(key)
{
case KEY_DOWN:
printw("DOWN\n");//注意linux的输出不是printf
break;
case KEY_UP:
printw("UP\n");
break;
case KEY_LEFT:
printw("LEFT\n");
break;
case KEY_RIGHT:
printw("RIGHT\n");
break;
}
}
endwin(); // 结束 ncurses
return 0;
}
第二阶段地图规划执行
第一步图框头
大小20X20。地图竖直方向上的边界“|”。地图水平方向上的边界”--”。贪吃蛇的身子”[ ]”。贪吃蛇的食物”##”
第一行打印“|-------------------------|”
#include <stdio.h>
#include <ncurses.h>
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
for(lie=0;lie<=20;lie++)//这里小于等于是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}
else
{
printw(" ");
}
}
}
}
}
int main()
{
//初始化
initNcurse();
gamePicture();
getch();
endwin(); // 结束 ncurses
return 0;
}
第二步图框完善
#include <stdio.h>
#include <ncurses.h>
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
// for(lie=0;lie<=20;lie++)//这里小于等于是为了图框更完美
// {
// if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
// {
// printw("|");
// }
// else
// {
// printw(" ");
// }
// }
//printw("\n");
}//上面这部分是第一行
if(hang>0 && hang<=19)//如果这里是if(hang>=0 && hang<=19)则可以把上面注释部分去掉如果不是则要取消注释
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");
}//
}
}
int main()
{
//初始化
initNcurse();
gamePicture();
getch();
endwin(); // 结束 ncurses
return 0;
}
第三步蛇的显示(静态)
#include <stdio.h>
#include <ncurses.h>
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake node1 = {2,2,NULL};//初始化蛇身
struct Snake node2 = {2,3,NULL};//初始化蛇身
struct Snake node3 = {2,4,NULL};//初始化蛇身
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = &node1;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void gamePicture()//图框
{
int hang;
int lie;
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");
}//
}
}
int main()
{
//初始化
initNcurse();
node1.next = &node2;//把蛇的每一段身子链接起来
node2.next = &node3;
gamePicture();
getch();
endwin(); // 结束 ncurses
return 0;
}
第四步蛇的显示(动态)
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head;//把链表头尾变成全局变量
struct Snake* tail;
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");
}//
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
tail->next = new;
tail = new;
}
void initSnake()//动态蛇身
{
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
int main()
{
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
getch();
endwin(); // 结束 ncurses
return 0;
}
第五步蛇开始移动
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head;//把链表头尾变成全局变量
struct Snake* tail;
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
move(0,0);//ncurse的库里面的光标移动函数
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");
}//
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
tail->next = new;
tail = new;
}
void initSnake()//动态蛇身
{
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
void deletNode()//移动身体(删除节点)
{
struct Snake* p;//释放内存避免内存泄露
p = head;
head = head->next;
free(p);
}
void moveSnake()//移动身体(增加节点)
{
addNode();
deletNode();
}
int main()
{
int con;
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
getch();
while(1)
{
con = getch();
if(con == KEY_RIGHT)
{
moveSnake();
gamePicture();//刷新
}
}
endwin(); // 结束 ncurses
return 0;
}
第六步撞墙
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head = NULL;//把链表头尾变成全局变量
struct Snake* tail = NULL;
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
move(0,0);//ncurse的库里面的光标移动函数
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");
}//
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
tail->next = new;
tail = new;
}
void initNcurse()//动态蛇身
{
struct Snake* p;//防止下面free()时出错
while(head != NULL)
{
p = head;
head = head->next;//撞墙才执行,清理原来占用的空间
free(p);
}
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
void deletNode()//移动身体(删除节点)
{
struct Snake* p;//释放内存避免内存泄露
p = head;
head = head->next;
free(p);
}
void moveSnake()//移动身体(增加节点)
{
addNode();
deletNode();
if(tail->hang ==0 || tail->lie == 0 || tail->hang == 0 || tail->lie == 20)//撞到边框重新开始
{
initSnake();
}
}
int main()
{
int con;
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
getch();
while(1)
{
con = getch();
if(con == KEY_RIGHT)
{
moveSnake();
gamePicture();//刷新
}
}
endwin(); // 结束 ncurses
return 0;
}
第七步蛇一直动
将主函数的循环改成这样就可以了
while(1)
{
moveSnake();
gamePicture();//刷新
refresh();//界面刷新
usleep(9000);//9毫秒
}
第八步随意改变移动方向
让蛇一开始向右动
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <pthread.h>
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
int key;
int dir;
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head = NULL;//把链表头尾变成全局变量
struct Snake* tail = NULL;
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
}
void gamePicture()//图框
{
int hang;
int lie;
move(0,0);//ncurse的库里面的光标移动函数
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");//可以把线程2里面的按键在这里打印
}
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
switch(dir)
{
case UP://向上跑
new->hang = tail->hang-1;
new->lie = tail->lie;
break;
case DOWN://向下跑
new->hang = tail->hang+1;
new->lie = tail->lie;
break;
case LEFT://向左跑
new->hang = tail->hang;
new->lie = tail->lie-1;
break;
case RIGHT://向右跑
new->hang = tail->hang;
new->lie = tail->lie+1;
break;
}
tail->next = new;
tail = new;
}
void initSnake()//动态蛇身
{
struct Snake* p;//防止下面free()时出错
dir = RIGHT;//让蛇一开始向右动
while(head != NULL)
{
p = head;
head = head->next;//撞墙才执行,清理原来占用的空间
free(p);
}
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
void deletNode()//移动身体(删除节点)
{
struct Snake* p;//释放内存避免内存泄露
p = head;
head = head->next;
free(p);
}
void moveSnake()//移动身体(增加节点)
{
addNode();
deletNode();
if(tail->hang ==0 || tail->lie == 0 || tail->hang == 0 || tail->lie == 20)//撞到边框重新开始
{
initSnake();
}
}
void* refreshJieMian()//线程1刷新界面
{
while(1)
{
moveSnake();
gamePicture();//刷新
refresh();//界面刷新
usleep(300000);//9毫秒
}
}
void* changerDir()//线程2修改方向
{
while(1)
{
key = getch();//获取用户输入
switch(key)
{
case KEY_DOWN:
dir = DOWN;//改变运动方向
break;
case KEY_UP:
dir = UP;
break;
case KEY_LEFT:
dir = LEFT;
break;
case KEY_RIGHT:
dir = RIGHT;
break;
}
}
}
int main()
{
//定义线程
pthread_t t1;
pthread_t t2;
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
pthread_create(&t1,NULL,refreshJieMian,NULL);//调用线程
pthread_create(&t2,NULL,changerDir,NULL);//调用线程
while(1);//循环线程
getch();
endwin(); // 结束 ncurses
return 0;
}
第九步优化第八步的代码(掉头不合理的问题)
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <pthread.h>
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
int key;
int dir;
struct Snake
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head = NULL;//把链表头尾变成全局变量
struct Snake* tail = NULL;
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
noecho();//查阅资料如果没有这个函数,系统可能会打印一些乱码
}
void gamePicture()//图框
{
int hang;
int lie;
move(0,0);//ncurse的库里面的光标移动函数
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng");//可以把线程2里面的按键在这里打印
}
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
switch(dir)
{
case UP://向上跑
new->hang = tail->hang-1;
new->lie = tail->lie;
break;
case DOWN://向下跑
new->hang = tail->hang+1;
new->lie = tail->lie;
break;
case LEFT://向左跑
new->hang = tail->hang;
new->lie = tail->lie-1;
break;
case RIGHT://向右跑
new->hang = tail->hang;
new->lie = tail->lie+1;
break;
}
tail->next = new;
tail = new;
}
void initSnake()//动态蛇身
{
struct Snake* p;//防止下面free()时出错
dir = RIGHT;//让蛇一开始向右动
while(head != NULL)
{
p = head;
head = head->next;//撞墙才执行,清理原来占用的空间
free(p);
}
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
void deletNode()//移动身体(删除节点)
{
struct Snake* p;//释放内存避免内存泄露
p = head;
head = head->next;
free(p);
}
void moveSnake()//移动身体(增加节点)
{
addNode();
deletNode();
if(tail->hang ==0 || tail->lie == 0 || tail->hang == 0 || tail->lie == 20)//撞到边框重新开始
{
initSnake();
}
}
void* refreshJieMian()//线程1刷新界面
{
while(1)
{
moveSnake();
gamePicture();//刷新
refresh();//界面刷新
usleep(300000);//9毫秒
}
}
void turn(int direction)//优化转弯(线程2)
{
if(abs(dir) != abs(direction))//abs函数用来取绝对值C库里面的
{
dir = direction;
}
}
void* changerDir()//线程2修改方向
{
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()
{
//定义线程
pthread_t t1;
pthread_t t2;
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
pthread_create(&t1,NULL,refreshJieMian,NULL);//调用线程
pthread_create(&t2,NULL,changerDir,NULL);//调用线程
while(1);//循环线程
getch();
endwin(); // 结束 ncurses
return 0;
}
第十步随机出现食物
#include <stdio.h>
#include <stdlib.h>
#include <ncurses.h>
#include <pthread.h>
#define UP 1
#define DOWN -1
#define LEFT 2
#define RIGHT -2
struct Snake//蛇身的结构体
{
int hang;;
int lie;
struct Snake* next;
};
struct Snake* head = NULL;//把链表头尾变成全局变量
struct Snake* tail = NULL;
int key;
int dir;
struct Snake food;
void initFood()//蛇的食物
{
int x = rand()%20;//边框是20x20的,不能让食物超出范围
int y = rand()%20;
food.hang = x;
food.lie = y;
}
void initNcurse()//调用Ncurse库
{
initscr(); // 初始化 ncurses
keypad(stdscr,1);// 启用键盘特殊键捕捉
noecho();//查阅资料如果没有这个函数,系统可能会打印一些乱码
}
void gamePicture()//图框
{
int hang;
int lie;
move(0,0);//ncurse的库里面的光标移动函数
for(hang=0;hang<20;hang++)
{
if(hang == 0)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
}//上面这部分是第一行
if(hang>=0 && hang<=19)
{
for(lie=0;lie<=20;lie++)//这里小于等于也是为了图框更完美
{
if(lie == 0 || lie == 20)//这里小于等于也是为了图框更完美
{
printw("|");
}else if(snakeNode(hang,lie))//初始化蛇身
{
printw("[]");
}
else if(snakeFood(hang,lie))//如果显示的是食物
{
printw("##");//两个食物,因为蛇身体的符号占用了两个字符位置
}
else
{
printw(" ");
}
}
printw("\n");
}//上面这部分是中间其他行
if(hang == 19)
{
for(lie=0;lie<20;lie++)
{
printw("--");
}
printw("\n");
printw("qinzhifeng,key,food.hang=%d,food.lie=%d",key,food.hang,food.lie);//可以把线程2里面的按键在这里打印
}
}
}
int snakeNode(int i,int j)//蛇身
{
struct Snake* p;
p = head;
while(p != NULL)
{
if(p->hang == i && p->lie == j)
{
return 1;
}
p = p->next;
}
}
int snakeFood(int i,int j)//蛇的食物
{
if(food.hang == i && food.lie == j)
{
return 1;
}
return 0;
}
void addNode()//身体变长,尾部插入
{
struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新的身体
new->hang = tail->hang;
new->lie = tail->lie+1;
new->next = NULL;
switch(dir)
{
case UP://向上跑
new->hang = tail->hang-1;
new->lie = tail->lie;
break;
case DOWN://向下跑
new->hang = tail->hang+1;
new->lie = tail->lie;
break;
case LEFT://向左跑
new->hang = tail->hang;
new->lie = tail->lie-1;
break;
case RIGHT://向右跑
new->hang = tail->hang;
new->lie = tail->lie+1;
break;
}
tail->next = new;
tail = new;
}
void initSnake()//动态蛇身
{
struct Snake* p;//防止下面free()时出错
dir = RIGHT;//让蛇一开始向右动
while(head != NULL)
{
p = head;
head = head->next;//撞墙才执行,清理原来占用的空间
free(p);
}
initFood();//食物初始化
head = (struct Snake*)malloc(sizeof(struct Snake));//开辟空间给头
head->hang = 2;//初始蛇身
head->lie = 2;
head->next = NULL;
tail = head;
addNode();//调用一次,最开始是身体就长一节
addNode();
}
void deletNode()//移动身体(删除节点)
{
struct Snake* p;//释放内存避免内存泄露
p = head;
head = head->next;
free(p);
}
int ifSnakeDie()
{
struct Snake* p;
p = head;
if(tail->hang < 0 || tail->lie == 0 || tail->hang == 0 || tail->lie == 20)//撞到边框重新开始。如果tail->hang == 0去不了第一行
{
return 1;
}
while(p->next != NULL)
{
if(p->hang == tail->hang && p->lie == tail->lie)//咬到自己
{
return 1;
}
p = p->next;
}
return 0;
}
void moveSnake()//移动身体(增加节点)
{
addNode();
if(snakeFood(tail->hang,tail->lie))
{
initFood();//吃实物
}else
{
deletNode(); //没吃到
}
if(ifSnakeDie())
{
initSnake();
}
}
void* refreshJieMian()//线程1刷新界面
{
while(1)
{
moveSnake();
gamePicture();//刷新
refresh();//界面刷新
usleep(300000);//9毫秒
}
}
void turn(int direction)//优化转弯(线程2)
{
if(abs(dir) != abs(direction))//abs函数用来取绝对值C库里面的
{
dir = direction;
}
}
void* changerDir()//线程2修改方向
{
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()
{
//定义线程
pthread_t t1;
pthread_t t2;
//初始化
initNcurse();
//把蛇的每一段身子链接起来
initSnake();
gamePicture();
pthread_create(&t1,NULL,refreshJieMian,NULL);//调用线程
pthread_create(&t2,NULL,changerDir,NULL);//调用线程
while(1);//循环线程
getch();
endwin(); // 结束 ncurses
return 0;
}