目录
前言
我们上节通过Linux线程实现了两个while(1)同时运行,这样就可以一边控制方向一遍刷新出贪吃蛇的身体节点了。本节我们就来实现贪吃蛇四方向的移动。
(此图片为最终效果)
原代码预览
我们之前的代码是通过moveSnake()函数实现贪吃蛇的移动的:
cpp
#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()函数:
cpp
void moveSnake()
{
addNode();
deleNode();
if(tail ->hang == 0 || tail->lie == 0 || tail->hang == 20 || tail ->lie == 20)
{
initSnake();
}
}
可以很明显的看出主要是由addNode()和deleNode()两个函数控制。
解决方法⚠️
那我们有没有办法使这两个函数更智能呢?
(新节点的行和列坐标要根据方向来确定)那么我们来定义出方向的全局变量 。
cpp
#define UP 1
#define DOWN 2
#define LEFT 3
#define RIGHT 4
int dir;
并且我们在初始化贪吃蛇的时候加上初始方向(initsnake())。
下面为修改后的initSnake()函数
cpp
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()语句就可以满足我们的要求。
cpp
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()函数:
cpp
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
运行效果一🌧️:
运行效果二🍇:
运行效果三✅:
总结
我们本节实现了贪吃蛇四方向移动,按住上下左右四个键就会做出相同的反馈,是我们想要的效果😘。