1.基础要求
会C语言指针, C语言链表 , linux线程编程,了解C语言图形化编程(nucrses),linux简单指令
2.为什么要用nucrse及游戏效果界面
nucrses,其实已经被市场淘汰了,只是为了方便学习。
游戏效果界面:
凸(艹皿艹 ):为什么会底部会出现这一串数字,好丑
3.nucrse输入输出
#include <curses.h>//nucrses库调用
printw();//输出
initscr();//nucrses 函数初始化
getch();//输入
endwin();//调用nucrses后最后必须调用该函数,否则无法看到输入输出
move(x,y);//用来刷新游戏界面
noecho();//调用在刷新有些界面时,容易出现一些不该有的乱码,该函数能解决该问题
4.nucrses获取上下左右键
打开 nucrses库 查询宏定义的上下左右键值:vi /usr/include/curses.h
代码实现:
#include <curses.h>//调用该函数库
int main(){
int key;
initscr();//初始化函数
keypad(stdscr,1);//获取键值函数,1这里表示接受
while(1){
key=getch();//等待键值输入
switch(key){//上下左右键
case KEY_UP:printw("up\n");break;//上
case KEY_DOWN:printw("down\n");break;//下
case KEY_LEFT:printw("left\n");break;//左
case KEY_RIGHT:printw("right\n");break;//右
}
}
getch();
endwin();//这个函数必须有,不然无法输入输出
return 0;
}
运行结果:注意linux 中没有自带的nucrses库,编译时须在后面加 -lcurses
运行后按上下左右键,获取键值
5.地图规划
20 X 20 的方形界面(类似一个坐标系)
游戏地图见上面的游戏界面效果图
6.地图实现
地图实现分三步实现
第一步:打印第一行第一列
第二步:打印2至18行
第三步:打印19至20行
代码实现综合版:
#include <curses.h>
void initNcure(){
initscr();//初始化函数
keypad(stdscr,1);
}
void gameInterFace(){//游戏界面打印
int row;//定义行
int col;//定义列
for(row=0;row<20;row++){
if(row==0){//打印第一行
for(col=0;col<20;col++){//打印第1列
printw("--");
}
printw("\n");//打印完后换行
}
if(row>=0 && row<=19){//打印1-18行列
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){打印最后一行
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!\n");
}
}
}
int main(){
initNcure();//初始化函数
gameInterFace();//游戏界面
getch();//使控制台停留
endwin();
return 0;
}
运行结果: 还是丑
7.显示贪吃蛇的一个节点
经过上面的打印输出,就可以将整个游戏界面看做一个坐标系,下面将显示在(2,2)这个坐标位置显示蛇身的第一个节点
#include <curses.h>
typedef struct snakes{
int row;//行
int col;//列
struct snake* next;
}snake,*psnake;
snake node1={2,2,NULL};//定位蛇身的第一个节点
void initNcure(){
initscr();
keypad(stdscr,1);
}
void gameInterFace(){
int row;//定义行
int col;//定义列
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(node1.row==row && node1.col==col){//输出蛇身的第一个节点
printw("[]");//打印蛇身
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!\n");//最后打印一个作者,嘿嘿
}
}
}
int main(){
initNcure();//初始化函数
gameInterFace();//游戏界面
getch();
endwin();
return 0;
}
运行结果:
8.显示贪吃蛇完整身子
增加蛇身节点算法:
(0,0) | (0,1) | ||||||||||||||||||
(1,0) | (1,1) | (1,2) | |||||||||||||||||
(2,0) | (2,1) | (2.2) | (2,3) | (2,4) | |||||||||||||||
从上面表格可以看出,在坐标系中如果要增加蛇身只需要在 y后+1即可
#include <curses.h>
#include <stdlib.h>//分配地址空间所需头文件
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head;//全局变量蛇头
psnake tail;//全局变量蛇尾
void initNcure(){//初始化函数
initscr();
keypad(stdscr,1);
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;//遍历整个蛇身
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!\n");
}
}
}
void addNode(){//增加蛇身的节点
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;//横坐标不变,纵坐标+1 及完成蛇身节点的增加
new->next=NULL;
tail->next=new;
tail=new;
}
void initSnake(){//蛇身的初始化
head=(psnake)malloc(sizeof(snake));//给蛇身分配地址空间
head->row=2;
head->col=2;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
}
int main(){
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
getch();
endwin();
return 0;
}
运行结果:
9.贪吃蛇右移
要想实现蛇身的移动,只需要增加一个节点再删除一个节点即可,同时要不断的刷新游戏界面(使用move();函数即可)。
#include <curses.h>
#include <stdlib.h>
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head;//全局变量蛇头
psnake tail;//全局变量蛇尾
void initNcure(){//初始化函数
initscr();
keypad(stdscr,1);
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
move(0,0);//移动光标,用来刷新界面
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!\n");
}
}
}
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;
}
void initSnake(){//初始化蛇身
head=(psnake)malloc(sizeof(snake));
head->row=2;
head->col=2;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
}
void deleteSnake(){//删除一个头节点
psnake p=NULL;
p=head;
head=head->next;
free(p);//注意:释放空间,避免空间泄漏
}
void moveSnake(){//蛇身移动
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/ //这个注释掉的内容就是addNode();
addNode();//增加一个节点
deleteSnake();//删除一个节点
}
int main(){
int cont;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
while(1){
cont=getch();//等待键值输入
if(cont==KEY_RIGHT){//获取键值
moveSnake();//移动蛇身
gameInterFace();//刷新游戏界面
}
}
getch();
endwin();
return 0;
}
运行结果:
10.贪吃蛇撞墙
判断是否撞墙及判断游戏界面边界
void moveSnake(){
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/
addNode();//增加一个节点
deleteSnake();//删除一个节点,实现蛇身移动
if(tail->row==0 || tail->col==0 || tail->row==20 || tail->col==20){//判断是否撞墙
initSnake();
}
}
运行结果:撞墙后恢复到起始点
11.贪吃蛇自由向右行走
要想实现贪吃蛇自由向右行走,需要只需添加一个 fefresh();函数,使其不管的刷新,同时添加一个usleep(1000);降低一下刷新的速度。
#include <curses.h>
#include <stdlib.h>
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head=NULL;//全局变量蛇头
psnake tail=NULL;//全局变量蛇尾
void initNcure(){
initscr();
keypad(stdscr,1);
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
move(0,0);//移动光标,用来刷新界面
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!\n");
}
}
}
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;
}
void initSnake(){
psnake p=NULL;
while(head!=NULL){
p=head;
head=head->next;
free(p);//重新开始后需要释放空间
}
head=(psnake)malloc(sizeof(snake));
head->row=1;
head->col=1;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
}
void deleteSnake(){//删除一个头节点
psnake p=NULL;
p=head;
head=head->next;
free(p);//释放空间,避免空间泄漏
}
void moveSnake(){
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/
addNode();//增加一个节点
deleteSnake();//删除一个节点,实现蛇身移动
if(tail->row==0 || tail->col==0 || tail->row==20 || tail->col==20){//判断是否撞墙
initSnake();
}
}
int main(){
int cont;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
while(1){
moveSnake();//移动蛇身
gameInterFace();
refresh();//刷新界面
usleep(100000);//usleep() 毫秒/ sleep() 秒
}
getch();
endwin();
return 0;
}
运行结果:自己试试,截图不明显
12.贪吃蛇方向移动与游戏界面刷新
代码实现:加入前面的键值即可,但在此时在C语言中不能实现,需要加入linux 线程编程,方可实现,linux 线程编程将在后面说明
void* changeDirection(){//上下左右方向键
while(1){
key=getch();//等待输入键值
switch(key){
case KEY_DOWN:printw("DOWN");break;
case KEY_UP:printw("UP");break;
case KEY_LEFT:printw("LIFT");break;
case KEY_RIGHT:printw("RIGHT");break;
}
}
}
13.利用Linux线程编程实现三个while循环同时运行
代码实现:
int main(){
pthread_t k1;//linux线程标志
pthread_t k2;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
pthread_create(&k1,NULL,refreshGameFace,NULL);//线程1
pthread_create(&k2,NULL,changeDirection,NULL);//线程2
while(1);//主线程
getch();
endwin();
return 0;
}
实现三个while循环同时运行的步骤 :
(1).加入头文件 #include <pthread.h>
(2).定义两个线程标志 ,用来表示有几个线程
pthread_t k1;
pthread_t k2;
(3).调用线程运行函数 pthread_create(a,b,c,d);
总共需要传入4个数:a. 线程标志 b.NULL(一般都为空) c.要运行的函数名(该函数必须为函数指针类型) d.同b
那么这里为什么要使用线程?
因为C语言主函数只能实现一个while,不能在刷新页面的同时获取键值。
综合代码实现:
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head=NULL;//全局变量蛇头
psnake tail=NULL;//全局变量蛇尾
int key;
void initNcure(){
initscr();
keypad(stdscr,1);
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
move(0,0);//移动光标,用来刷新界面
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!,key=%d\n",key);
}
}
}
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;
}
void initSnake(){
psnake p=NULL;
while(head!=NULL){
p=head;
head=head->next;
free(p);//重新开始后需要释放空间
}
head=(psnake)malloc(sizeof(snake));
head->row=1;
head->col=1;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
}
void deleteSnake(){//删除一个头节点
psnake p=NULL;
p=head;
head=head->next;
free(p);//释放空间,避免空间泄漏
}
void moveSnake(){
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/
addNode();//增加一个节点
deleteSnake();//删除一个节点,实现蛇身移动
if(tail->row==0 || tail->col==0 || tail->row==20 || tail->col==20){//判断是否撞墙
initSnake();
}
}
void* refreshGameFace(){//刷新游戏界面
while(1){
moveSnake();//移动蛇身
gameInterFace();
refresh();//刷新界面
usleep(100000);//usleep() 毫秒/ sleep() 秒
}
moveSnake();//移动蛇身
gameInterFace();
refresh();//刷新界面
usleep(100000);//usleep() 毫秒/ sleep() 秒
}
}
void* changeDirection(){//上下左右方向键
while(1){
key=getch();//等待输入键值
switch(key){
case KEY_DOWN:printw("DOWN");break;
case KEY_UP:printw("UP");break;
case KEY_LEFT:printw("LIFT");break;
case KEY_RIGHT:printw("RIGHT");break;
}
}
}
int main(){
pthread_t k1;//linux线程标志
pthread_t k2;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
pthread_create(&k1,NULL,refreshGameFace,NULL);//线程1
pthread_create(&k2,NULL,changeDirection,NULL);//线程2
while(1);//主线程
getch();
endwin();
return 0;
}
14.实现贪吃蛇四个方向行走
实现蛇身上下左右的算法:(把下面看做一个坐标系)
(3,3) | (3,4) | ||||||||||||||||||
(4,3) | (4,4) | ||||||||||||||||||
向上:纵坐标不变,横坐标减一
向下:纵坐标不变,横坐标加一
向左:横坐标不变,纵坐标减一
向右:横坐标不变,纵坐标加一
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->next=NULL;
switch(dir){//控制蛇身上下左右
case UP :
new->row=tail->row-1;//控制蛇身上
new->col=tail->col;
break;
case DOWN:
new->row=tail->row+1;//控制蛇身下
new->col=tail->col;
break;
case LEFT :
new->row=tail->row;//控制蛇身左
new->col=tail->col-1;
break;
case RIGHT :
new->row=tail->row;//控制蛇身右
new->col=tail->col+1;
break;
}
tail->next=new;
tail=new;
}
15.解决不合理走位
通过取相同数的绝对值来控制蛇的不合理走位,同时对方向键进行优化
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>
#define UP 1//注意define 定义完没有;
#define DOWN -1
#define LEFT 2
#define RIGHT -2
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head=NULL;//全局变量蛇头
psnake tail=NULL;//全局变量蛇尾
int key;
int dir;
void initNcure(){
initscr();
keypad(stdscr,1);
noecho();//防止乱码出现
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
move(0,0);//移动光标,用来刷新界面
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!,key=%d\n",key);
}
}
}
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->next=NULL;
switch(dir){//控制蛇身上下左右
case UP :
new->row=tail->row-1;
new->col=tail->col;
break;
case DOWN:
new->row=tail->row+1;
new->col=tail->col;
break;
case LEFT :
new->row=tail->row;
new->col=tail->col-1;
break;
case RIGHT :
new->row=tail->row;
new->col=tail->col+1;
break;
}
tail->next=new;
tail=new;
}
void initSnake(){
psnake p=NULL;
dir=RIGHT;
while(head!=NULL){
p=head;
head=head->next;
free(p);//重新开始后需要释放空间
}
head=(psnake)malloc(sizeof(snake));
head->row=1;
head->col=1;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
addNode();
}
void deleteSnake(){//删除一个头节点
psnake p=NULL;
p=head;
head=head->next;
free(p);//释放空间,避免空间泄漏
}
void moveSnake(){
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/
addNode();//增加一个节点
deleteSnake();//删除一个节点,实现蛇身移动
if(tail->row==0 || tail->col==0 || tail->row==20 || tail->col==20){//判断是否撞墙
initSnake();
}
}
void* refreshGameFace(){//刷新游戏界面
while(1){
moveSnake();//移动蛇身
gameInterFace();
refresh();//刷新界面
usleep(100000);//usleep() 毫秒/ sleep() 秒
}
}
void turn (int direction){//使蛇身移动正常
if(abs(dir) != abs(direction)){//abs();取绝对值函数;功能,不能直接同时一上一下或一左一右
dir=direction;
}
}
void* changeDirection(){//上下左右方向键
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 k1;//linux线程标志
pthread_t k2;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
pthread_create(&k1,NULL,refreshGameFace,NULL);//线程1,刷新界面
pthread_create(&k2,NULL,changeDirection,NULL);//线程2,改变方向
while(1);//主线程
getch();
endwin();
return 0;
}
16.放置贪吃蛇食物
snake food;//定义新的变量
void initFood(){//定义食物位置
static int x=4;//静态变量
static int y=5;
food.row=x;
food.col=y;
x+=2;//使食物出现的位置不同,但不是随机出现
y+=2;
}
17.食物位置随机
rand();产生随机数函数,通过取余来固定食物出现的边界
void initFood(){//定义食物位置
int x=rand()%20;//产生随机食物
int y=rand()%20;
food.row=x;
food.col=y;
}
18.总结
先把完整代码放在这里吧!安装了nucrse库的可以试试,后面有时间更新一个字符串的贪吃蛇,同时再写总结吧!
#include <curses.h>
#include <stdlib.h>
#include <pthread.h>
#define UP 1//注意define 定义完没有;
#define DOWN -1
#define LEFT 2
#define RIGHT -2
typedef struct snakes{
int row;//行
int col;//列
struct snakes* next;
}snake,*psnake;
psnake head=NULL;//全局变量蛇头
psnake tail=NULL;//全局变量蛇尾
int key;
int dir;
snake food;
void initFood(){//定义食物位置
int x=rand()%20;//产生随机食物
int y=rand()%20;
food.row=x;
food.col=y;
}
void initNcure(){
initscr();
keypad(stdscr,1);
noecho();//防止乱码出现
}
int whetherSnakeNode(int i,int j){//确定坐标节点
psnake p;
p=head;
while(p!=NULL){
if(p->row==i && p->col==j){
return 1;
}
p=p->next;
}
return 0;
}
int whetherSnakeFood(int i,int j){//确定食物坐标节点
if(food.row==i && food.col==j){
return 1;
}
return 0;
}
void gameInterFace(){
int row;//定义行
int col;//定义列
move(0,0);//移动光标,用来刷新界面
for(row=0;row<20;row++){
if(row==0){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
}
if(row>=0 && row<=19){
for(col=0;col<=20;col++){
if(col==0 || col==20){
printw("|");
}
else if(whetherSnakeNode(row,col)){//扫描输出
printw("[]");
}
else if(whetherSnakeFood(row,col)){
printw("##");
}
else{
printw(" ");
}
}
printw("\n");
}
if(row==19){
for(col=0;col<20;col++){
printw("--");
}
printw("\n");
printw("By MicroLiang!,key=%d\n",key);
printw("food.row=%d food.col=%d\n",food.row,food.col);
}
}
}
void addNode(){
psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->next=NULL;
switch(dir){//控制蛇身上下左右
case UP :
new->row=tail->row-1;
new->col=tail->col;
break;
case DOWN:
new->row=tail->row+1;
new->col=tail->col;
break;
case LEFT :
new->row=tail->row;
new->col=tail->col-1;
break;
case RIGHT :
new->row=tail->row;
new->col=tail->col+1;
break;
}
tail->next=new;
tail=new;
}
void initSnake(){//初始化蛇身
psnake p=NULL;
dir=RIGHT;
while(head!=NULL){
p=head;
head=head->next;
free(p);//重新开始后需要释放空间
}
initFood();//初始化食物
head=(psnake)malloc(sizeof(snake));
head->row=1;
head->col=1;
head->next=NULL;
tail=head;
addNode();//增加蛇身
addNode();
addNode();
}
void deleteSnake(){//删除一个头节点
psnake p=NULL;
p=head;
head=head->next;
free(p);//释放空间,避免空间泄漏
}
int ifSnakeDie(){
psnake p=NULL;
p=head;
if(tail->row<0 || tail->col==0 || tail->row==20 || tail->col==20){//判断是否撞墙
return 1;
}
while(p->next!=NULL){//
if(p->row==tail->row && p->col==tail->col){//判断节点是否重合,及是否撞到自己
return 1;
}
p=p->next;
}
return 0;
}
void moveSnake(){
/*psnake new=NULL;
new=(psnake)malloc(sizeof(snake));
new->row=tail->row;
new->col=tail->col+1;
new->next=NULL;
tail->next=new;
tail=new;*/
addNode();//增加一个节点
if(whetherSnakeFood(tail->row,tail->col)){//判断是否有食物
initFood();
}
else{
deleteSnake();//删除一个节点,实现蛇身移动
}
if(ifSnakeDie()){//判断是否死亡
initSnake();
}
}
void* refreshGameFace(){//刷新游戏界面
while(1){
moveSnake();//移动蛇身
gameInterFace();
refresh();//刷新界面
usleep(100000);//usleep() 毫秒/ sleep() 秒
}
}
void turn (int direction){//使蛇身移动正常
if(abs(dir) != abs(direction)){//abs();取绝对值函数;功能,不能直接同时一上一下或一左一右
dir=direction;
}
}
void* changeDirection(){//上下左右方向键
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 k1;//linux线程标志
pthread_t k2;
initNcure();//初始化函数
initSnake();//初始化蛇身
gameInterFace();//游戏界面
pthread_create(&k1,NULL,refreshGameFace,NULL);//线程1,刷新界面
pthread_create(&k2,NULL,changeDirection,NULL);//线程2,改变方向
while(1);//主线程
getch();
endwin();
return 0;
}