#include//在linux上用ncurses库写的 #include #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;//在食物可能的地方rand对20取余给食物一个坐标,此地图是20*20的地图 int y=rand()%20; food.hang=x;//贪吃蛇的的坐标显示值 food.lie=y; } void initNcurse(){//这个是ncurses库的初始化, initscr();//调用ncurses库 keypad(stdscr,1);//获取键盘的功能键功能 noecho();//这个是的ncurses 的一个小bug,防止显示时乱码 } int hasSnakenode(int i,int j){//遍历贪吃蛇蛇这个链表,把地图里面的坐标传过来 struct Snake *p; p=head; while(p!=NULL){ if(p->hang == i && p->lie == j){//把贪吃蛇的链表里面的行列与地图坐标对比,返回1到gamePic里面,使其显示贪吃蛇的身子[]; return 1; } p=p->next; } return 0; } int hasFood(int han,int nie)//在地图中显示食物的函数 { if(food.hang==han&&food.lie==nie) { return 1; } return 0; } void gamePic()//制作20*20的地图 { int hang; int lie; move(0,0); for(hang=0;hang<=20;hang++){ if(hang==0 || hang==20){ for(lie=0;lie<20;lie++){ printw("--");//上下界限 }printw("n"); } else{ for(lie=0;lie<=20;lie++){ if(lie==0 || lie==20){ printw("|");//左右边界 } else if(hasSnakenode(hang,lie)){//显示蛇身 printw("[]"); } else if(hasFood(hang,lie)){//显示食物 printw("##"); } else{ printw(" ");//地图空白处 } }printw("n"); } } printw("%dn,%d,%dn",key,food.hang,food.lie); } void addNode()//添加蛇的身子的节点 { struct Snake *new = (struct Snake *)malloc(sizeof(struct Snake)); 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; 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(); } void deletSnake(){//蛇在移动的时候,删除头节点,实现画面中的蛇移动 struct Snake *p; p=head; head=head->next; free(p); } int ifSnakedie()//蛇死亡的几种死法 { struct Snake *p=head; if(tail->hang==0||tail->hang==20||tail->lie==0||tail->lie==20){ 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(hasFood(tail->hang,tail->lie)) { initFood(); } else{ deletSnake(); } if(ifSnakedie()){ initSnake(); } } void refreshJieMian() { while(1){ moveSnake(); gamePic(); refresh();//刷新界面 usleep(100000);//设置睡眠时间 } } 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_RIGHT: turn(RIGHT); break; case KEY_LEFT: turn(LEFT); break; } } } int main() { pthread_t t1;//利用线程来解决可以同时刷新界面显示和同时按下按键的问题 pthread_t t2; initNcurse(); initSnake(); gamePic(); pthread_create(&t1,NULL,refreshJieMian,NULL); pthread_create(&t2,NULL,changeDir,NULL); while(1); getch(); endwin();//这个是ncurse库的结束函数。 return 0;}
1.先设计地图的大小
2.了解整体贪吃蛇的链表结构和显示过程
3.键盘的上下左右的功能的实现用的是ncurses实现
4.贪吃蛇的的上下左右移动时链表是如何改变的,整体链表的头删掉,尾巴增加,这里的头和胃是链表的头和尾,不是贪吃蛇的头和尾;
5.食物的显现和随机变化
6.当贪吃蛇吃到食物时,链表又是如何变化的,链表的头不做删除,链表的尾巴做删除
7.当贪吃蛇碰到自己的身子时,重新开始
以上7点是整体的大体编写思路,如有更好的思路可以留言



