代码开发流程:nucrse初始化->地图实现->贪吃蛇自由向右行走->双线程实现自由行走和刷新页面->实物随机分布->要死自己来结束游戏。
1、为什么我们需要使用ncurse?
因为在玩贪吃蛇时,我们需要一个很快的按键响应,ncurse在即时按键响应这方面做得比较好,当然现在已经很落后了。
2、C语言中获取键盘输入
initscr();//nucrse页面初始化函数
printw("This is a snake");//nucrse模式下的printf
getch();//等待用户输入,如果没有这句话程序退出看不到运行结果也就是说看不到上面那句话
endwin();//程序退出
keypad(stdscr,1);//从标准键盘获得输入
3、地图实现
所有的运行函数一定要放在getch()之前
void gameMap()
{
int hang;
int lie;
move(0,0);
for(hang = 0;hang < 30;hang++)
{
if(hang == 0||hang == 29)
{
for(lie = 0;lie < 30;lie++)
{
printw("--");
}
printw("\n");
}
if(hang > 0 && hang < 29)
{
for(lie = 0;lie < 31;lie++)
{
if(lie == 0 || lie == 30)
{
printw("|");
}
else{
printw(" ");
}
}
printw("\n");
}
}
}
4、动态创建蛇的身子
1、初始化蛇头尾结点
void initsnake()
{
head = (struct snake *)malloc(struct snake);//文件开始即被定义不会轻易改变
head->hang = 2;
head->lie = 2;
head->next = NULL;
tail = head;
addsnake();
}
2、动态添加尾结点
void addsnake()
{
struct snake *new;
new = (struct snake*)malloc(struct snake);
new->hang = tail->hang;
new->lie = tail->lie+1;//先给new赋值
tail->next = new;
tail = new;//new成为新尾巴
}
3、获取蛇位置标记以在地图中显示
int getmark(int i,int j)
{
struct snake *p = head;
while(p != NULL)
{
if(p->hang == i&&p->lie == j)
{
return 1;
}
p = p->next;
}
return 0;
}
5、蛇向右移动
原理:移动一下删掉头结点,增加尾结点
void addsnake()
{
struct snake *new;
new = (struct snake*)malloc(sizeof(struct snake));
new->hang = tail->hang;
new->lie = tail->lie+1;//先给new赋值
tail->next = new;
tail = new;//new成为新尾巴
}
void delsnake()
{
head = head->next;
}
void movesnake()
{
addsnake();
delsnake();
}
自动向右移动:
while(1)
{
movesnake();
creatmap();
}
向右移动过程中撞墙
void delnode()
{
struct snake *p = NULL;
p = head;
head = head->next;
free(p);
}
void initsnake()//贪吃蛇重置
{
struct snake *p = NULL;
while(head != NULL)//如果因为撞墙重置则把原来的蛇节点全部释放
{
p = head;
head= head->next;
free(p);
}
head = (struct snake *)malloc(sizeof(struct snake));
head->hang = 1;
head->lie = 2;
head->next = NULL;
tail = head;
addnode();
addnode();
addnode();
}
void movesnake()//移动中撞墙重置
{
addnode();
delnode();
if(tail->hang == 0 ||tail->hang == 29 ||tail->lie ==0 ||tail->lie ==30)
{
initsnake();
}
}
6、双线程引入同时刷新按键和页面
界面的刷新
void* refreshwindow()
{
while(1)
{
movesnake();
gamemap();
refresh();//refresh map
usleep(100000);
}
}
贪吃蛇改变方向
void* changedir()
{
keypad(stdscr,1);
while(1)
{
key = getch();
switch(key)
{
case KEY_UP:
printw("UP");
dir = UP;
break;
case KEY_DOWN:
printw("DOWN");
dir = DOWN;
break;
case KEY_LEFT:
printw("LEFT");
dir = LEFT;
break;
case KEY_RIGHT:
printw("RIGHT");
dir = RIGHT;
break;
}
}
}
主要是对增加节点进行改进
void addnode()
{
struct snake *new = NULL;
new = (struct snake*)malloc(sizeof(struct snake));
new->next = NULL;
switch(dir)
{
case UP:
new->hang = tail->hang-1;
new->lie = tail->lie;
printf("11111\n");
break;
case DOWN:
new->hang = tail->hang+1;
new->lie = tail->lie;
printf("2222\n");
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;
}
7、方向键控制蛇节点
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 turn(int direction)
{
if(abs(dir) != abs(direction))
{
dir =direction;
}
}
void* changeDir()
{
while(1)
{
key = getch();
switch(key)
{
//这四个为ncurses自带的表示方向的宏。
case KEY_DOWN:
turn(DOWN);
break;
case KEY_UP:
turn(UP);
break;
case KEY_LEFT:
turn(LEFT);
break;
case KEY_RIGHT:
turn(RIGHT);
break;
}
}
}
8、绝对值解决贪吃蛇不合理走位
void turn(int direction)
{
if(abs(dir) != abs(direction))//如果旧的方向不等于新的方向就不改变贪吃蛇走位
{
dir = direction;
}
}
void* changedir()
{
keypad(stdscr,1);
while(1)
{
key = getch();
switch(key)
{
case KEY_UP:
turn(UP);
break;
case KEY_DOWN:
turn(DOWN);
break;
case KEY_LEFT:
turn(LEFT);
break;
case KEY_RIGHT:
turn(RIGHT);
break;
}
}
}
9、初始化食物
void initfood()//初始化食物位置
{
srand((unsigned)time(NULL));
int x = rand()%27;
int y = rand()%27;
food.hang = x;
food.lie = y;
}
int getfood(int i,int j)//给定标志位以在地图中显示
{
if(food.hang == i&&food.lie == j)
{
return 1;
}
return 0;
}
int snakeDie()//到达地图边界死亡或者撞死自己死亡
{
struct snake *p = NULL;
p = head;
if(tail->hang < 0||tail->hang == 29||tail->lie == 0||tail->lie == 29)
{
return 1;
}
while(p->next != NULL){//如果直接p判断肯定每次这个条件都成立,每次都能遍历到蛇末端
if(p->hang == tail->hang && p->lie == tail->lie){
return 1;
}
p = p->next;
}
return 0;
}
void movesnake()//移动中尾巴撞上食物则只增加节点重置食物,蛇死了就重置蛇。否则的话只自由移动
//朝哪个方向就向哪个方向增加节点
{
addnode();
if(getfood(tail->hang,tail->lie))
{
initfood();
}
else
{
delnode();
}
if(snakeDie())
{
initsnake();
}
}
贪吃蛇完整代码
#include <curses.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
#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;
struct snake food;
void initfood()
{
srand((unsigned)time(NULL));
int x = rand()%27 + 1;
int y = rand()%27 + 1;
food.hang = x;
food.lie = y;
}
int getfood(int i,int j)
{
if(food.hang == i&&food.lie == j)
{
return 1;
}
return 0;
}
int key;
int dir;
void addnode()
{
struct snake *new = NULL;
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 delnode()
{
struct snake *p = NULL;
p = head;
head = head->next;
free(p);
}
void initsnake()
{
struct snake *p = NULL;
dir = RIGHT;
while(head != NULL)
{
p = head;
head= head->next;
free(p);
}
head = (struct snake *)malloc(sizeof(struct snake));
head->hang = 1;
head->lie = 2;
head->next = NULL;
tail = head;
addnode();
addnode();
addnode();
}
int snakeDie()
{
struct snake *p = NULL;
p = head;
if(tail->hang < 0||tail->hang == 29||tail->lie == 0||tail->lie == 29)
{
return 1;
}
while(p->next != NULL){//如果直接p判断肯定每次这个条件都成立,每次都能遍历到蛇末端
if(p->hang == tail->hang && p->lie == tail->lie){
return 1;
}
p = p->next;
}
return 0;
}
void movesnake()
{
addnode();
if(getfood(tail->hang,tail->lie))
{
initfood();
}
else
{
delnode();
}
if(snakeDie())
{
initsnake();
}
}
int getsnake(int hang,int lie)
{
struct snake *p = head;
while(p != NULL)
{
if(hang == p->hang && lie == p->lie)
{
return 1;
}
p = p->next;
}
return 0;
}
void gamemap()
{
int hang;
int lie;
move(0,0);
for(hang = 0;hang <= 30;hang++)
{
if(hang == 0||hang == 29)
{
for(lie = 0;lie < 30;lie++)
{
printw("--");
}
printw("\n");
}
if(hang > 0 && hang < 29)
{
for(lie = 0;lie < 31;lie++)
{
if(lie == 0 || lie == 30)
{
printw("|");
}
else if(getsnake(hang,lie))
{
printw("[]");
}
else if(getfood(hang,lie))
{
printw("##");
}
else
{
printw(" ");
}
}
printw("\n");
}
if(hang == 30)
{
printw("by Yang Xiao you scores:\n");
}
}
}
void turn(int direction)
{
if(abs(dir) != abs(direction))
{
dir = direction;
}
}
void* refreshwindow()
{
while(1)
{
movesnake();
gamemap();
refresh();//refresh map
usleep(100000);
}
}
void* changedir()
{
keypad(stdscr,1);//非常关键,用于从键盘获取方向键操作
while(1)
{
key = getch();//读取ncurses界面的输入,不能用getchar()
switch(key)
{
case KEY_UP:
turn(UP);
break;
case KEY_DOWN:
turn(DOWN);
break;
case KEY_LEFT:
turn(LEFT);
break;
case KEY_RIGHT:
turn(RIGHT);
break;
}
}
}
int main()
{
pthread_t t1;
pthread_t t2;
noecho();
initscr();
initfood();
initsnake();
gamemap();
pthread_create(&t1,NULL,refreshwindow,NULL);
pthread_create(&t2,NULL,changedir,NULL);
while(1);
endwin();
return 0;
}