目录
前言
原代码预览
解决方法⚠️
运行效果
总结
前言
我们上节通过Linux线程实现了两个while(1)同时运行,这样就可以一边控制方向一遍刷新出贪吃蛇的身体节点了。本节我们就来实现贪吃蛇四方向的移动。
(此图片为最终效果)
原代码预览
我们之前的代码是通过moveSnake()函数实现贪吃蛇的移动的:
#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>struct Snake
{int hang;int lie;struct Snake * next;
};struct Snake * head = NULL;
struct Snake * tail = NULL;int key;void initNcurse()
{initscr();keypad(stdscr,1);
}int hasSnakeNode(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 gamePic()
{int hang;int lie;move(0,0);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(hasSnakeNode(hang,lie)) printw("[]");else printw(" ");}printw("\n");}if(hang == 19){for(lie = 0;lie < 20;lie ++){printw("--");}printw("\n");printw("by beiweiqiuAC,%d\n",key);}}}void addNode()
{struct Snake * new = (struct Snake *)malloc(sizeof(struct Snake));new->hang = head->hang;new->lie = tail->lie+1;new->next = NULL;tail->next = new;tail = new;
}void initSnake(){struct Snake * p;while(head != NULL){p = head;head = head -> next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}void deleNode()
{// struct Snake * p;// p = head;head = head ->next;// free(p);
}void moveSnake()
{addNode();deleNode();if(tail ->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail ->lie == 20){initSnake();}
}void* refreshJieMian()
{while(1){moveSnake();gamePic();refresh();usleep(100000);}
}void* changeDir()
{while (1){key = getch();switch (key){case 0402:printw("DOWN\n");break;case 0403:printw("UP\n");break;case 0404:printw("LEFT\n");break;case 0405:printw("RIGHT\n");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();return 0;
}
那么我们详细看一下moveSnake()函数:
void moveSnake()
{addNode();deleNode();if(tail ->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail ->lie == 20){initSnake();}
}
可以很明显的看出主要是由addNode()和deleNode()两个函数控制。
解决方法⚠️
那我们有没有办法使这两个函数更智能呢?
(新节点的行和列坐标要根据方向来确定)那么我们来定义出方向的全局变量 。
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
int dir;
并且我们在初始化贪吃蛇的时候加上初始方向(initsnake())。
下面为修改后的initSnake()函数
void initSnake(){struct Snake * p;dir = RIGHT;while(head != NULL){p = head;head = head -> next;free(p);}head = (struct Snake *)malloc(sizeof(struct Snake));head->hang = 1;head->lie = 1;head->next = NULL;tail = head;addNode();addNode();addNode();addNode();
}
上文可以知道,我们显示贪吃蛇的节点,改变贪吃蛇的节点是通过addNode()和deleNode()两个函数,那么我们只需要在addNode()增加上下一节点位置的判断即可。
在贪吃蛇移动的过程中只有四种情况,上下左右,所以简单的switch()语句就可以满足我们的要求。
void addNode()
{struct Snake * new = (struct Snake *)malloc(sizeof(struct Snake));new->next = NULL;switch(dir){case UP:new->hang = head->hang - 1;new->lie = tail->lie;break;case DOWN:new->hang = head->hang + 1;new->lie = tail->lie;break;case LEFT:new->hang = head->hang;new->lie = tail->lie - 1;break;case RIGHT:new->hang = head->hang;new->lie = tail->lie + 1;break;}tail->next = new;tail = new;
}
于此同时我们也需要修改changeDir()函数:
void* changeDir()
{while (1){key = getch();switch (key){case 0402:dir = DOWN;break;case 0403:dir = UP;break;case 0404:dir = LEFT;break;case 0405:dir = RIGHT;break;}}
}
运行效果
该文件默认命名为snake11.c
打开终端输入以下指令编译该文件:
gcc snake11.c -lcurses
系统会默认生成一个名为“a.out”的可执行文件,输入以下指令执行该程序:
./a.out
运行效果一🌧️:
运行效果二🍇:
运行效果三✅:
总结
我们本节实现了贪吃蛇四方向移动,按住上下左右四个键就会做出相同的反馈,是我们想要的效果😘。