#include<ncurses.h>
#include<stdlib.h>
#include<pthread.h>/*线程的头文件*/
#include <unistd.h>/*运用sleep()*/
struct she
{
int hang;
int lie;
struct she *next;
};
struct she *head=NULL;
struct she *tall=NULL;
struct she food;
int key;
int dir;
#define UP 1
#define RIGHT 2
#define LEFT -2
#define DOWN -1
int findshe(int i,int j)/*判断蛇的位置(当蛇身所设节点位置与
图形界面所在位置重合既显示“{}”),返回1或者0显示蛇身*/
{
struct she *p;
p=head;
while(p!=NULL)
{
if(p->hang==i&&p->lie==j)
return 1;
p=p->next;
}
return 0;
}
void initNcurses()
{
initscr();//用户界面的初始化函数,在开始curses编程之前,必须使用initscr()这个函数来开启curses模式//
keypad(stdscr,1);
/*呼叫 keypad 时须传入两个值, win 为一 WINDOW 型态指标,
通常传入标准输出入萤幕 stdscr. bf 为 TRUE 或 FALSE.
当开启 keypad 後, 可以使用键盘上的一些特殊字元,
如上下左右>等方向键, curses 会将这些特殊字元转
换成 curses.h 内定义的一些特殊键. 这些定义的特殊键
通常以 KEY_ 开头.*/
}
void setfood()
{
int x=rand()%19;
/*生成蛇的食物,rand()函数为随机生成数,
由于界面是20x20所以需要通过求余来获得X,Y*/
int y=rand()%19;
if(x==0)
x+=1;
if(y==0)
y+=1;
food.hang=x;
food.lie=y;
}
int hasfood(int i,int j)
{
if(food.hang==i&&food.lie==j)
/*判断食物的节点是否与图形节点重合*/
return 1;
return 0;
}
void gameinterface()/*蛇的游戏范围即游戏框图*/
{
int line;
int column;
move(0,0);
/*移动光标*/
for(line=0;line<20;line++)
{
if(line==0||line==19)
{
for(column=0;column<20;column++)
printw("--");
printw("\n");
}
else
for(column=0;column<20;column++)
{
if(column==0)
printw("| ");
else if(column==19)
{
printw(" |");
printw("\n");
}
else if(findshe(line,column))
printw("{}");
/*通过函数findshe()返回1与否来显示蛇的有无*/
else if(hasfood(line,column))
printw("$$");
/*通过函数hasfood()返回1与否来显示食物的有无*/
else
printw(" ");
}
}
printf("\n");
printw("By YGL,key=%d,food.hang=%d,food.lie=%d\n",key,food.hang,food.lie);
}
void addpoint() /*在节点尾末加上节点*/
{
struct she *new=(struct she *)malloc(sizeof(struct she));
new->next=NULL;
switch(dir)
{
case UP:
new->hang=tall->hang-1;
new->lie=tall->lie;
new->next=NULL;
break;
case DOWN:
new->hang=tall->hang+1;
new->lie=tall->lie;
new->next=NULL;
break;
case RIGHT:
new->hang=tall->hang;
new->lie=tall->lie+1;
new->next=NULL;
break;
case LEFT:
new->hang=tall->hang;
new->lie=tall->lie-1;
new->next=NULL;
break;
}
tall->next=new;
tall=new;
}
void initshe()/*放置蛇进入游戏界面以及蛇撞墙后重新放置*/
{
struct she *p;
dir=RIGHT;
while(head!=NULL)
{
p=head;
head=head->next;
free(p);
}
head=(struct she *)malloc(sizeof(struct she));
head->hang=1;
head->lie=1;
head->next=NULL;
tall=head;/*蛇的初始位置*/
addpoint();
addpoint();
/*蛇的初始长度1+2*/
}
void deletepoint()/*删除第一个节点*/
{
head=head->next;
}
int ifshedie()
{
struct she *p;
p=head;
if(tall->hang==0||tall->hang==19||tall->lie==0||tall->lie==19)
/*判断蛇是否撞墙*/
return 1;
while(p->next!=NULL)/*判断蛇是否吃到自己*/
{
if(p->hang==tall->hang&&p->lie==tall->lie)
return 1;
p=p->next;
}
return 0;
}
void SHEMOVE()/*控制蛇的移动函数*/
{
addpoint();
if(hasfood(tall->hang,tall->lie))
setfood();
else
{
deletepoint();
}
if(ifshedie())
initshe();
}
void *refreshjm()
{
while(1)
{
SHEMOVE();
gameinterface();
usleep(150000);
refresh();
/*之前的printw只是打印到逻辑屏幕,而refresh函数会依据逻辑屏幕的内容,刷新到物理屏幕。*/
}
}
void turn(int a)
{
if(abs(dir)!=abs(a))
/*求abs(a)整数的绝对值*/
dir=a;
return;
}
void *cdir()
{
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;
/*当前Linux中可理解为:typedef unsigned long int pthread_t;*/
pthread_t t2;
initNcurses();
initshe();
setfood();
gameinterface();
pthread_create(&t1, NULL, cdir, NULL);
pthread_create(&t2, NULL, refreshjm, NULL);
/*参数1:传出参数,保存系统为我们分配好的线程ID
参数2:通常传NULL,表示使用线程默认属性。若想使用具体属性也可以修改该参数。
参数3:函数指针,指向线程主函数(线程体),该函数运行结束,则线程结束。
参数4:线程主函数执行期间所使用的参数,如要传多个参数, 可以用结构封装。*/
while(1);
getch();
/*从键盘读取一个字元. (注意! 传回的是整数值)
在这儿的作用及等待用户输入,否则界面将直接退出,
看不到任何输出*/
endwin();//结束curses编程时,最后调用的一个函数//
return 0;
}
注意:因为初学,所以以防忘记。
编译时:
gcc test8.c -o snack -lncurse -lpthread