基于ncurse的链表贪吃蛇

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;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值