一、Ncurses库简介:
1、curses是一个在Linux/Unix下广泛应用的图形函数库, 作用是可以在终端内绘制简单的图形用户界面。
2、Nurses库头文件:#include <curses.h>
编译时要链接 -lcurses
3、本程序中使用的函数 :
#include <curses.h>
1)initscr(); 初始化屏幕,启动curses模式
2)getch(); 获取一个字符 例: int c = getch();
3)endwin(); 退出curses模式
4)move(0,0); 锁定光标在(0:0)
5)refresh(); 刷新界面
6)noecho(); 不显示按键符号
7)rand(); 生成随即数
8)在Ncurses中使用功能键必须调用:key(stdscr,1);
stdscr:激活功能键
1:是否激活,1:是
#include <unistd.h>
1)sleep(); 时间函数(秒)
2)usleep(); 时间函数(微秒)
二、贪吃蛇地图规划:
贪吃蛇竖直方向上的边界:“|”
贪吃蛇水平方向上的边界:“--”
贪吃蛇身体:[ ]
贪吃蛇食物:##
地图边界:行x列 18x25
三、Linux线程
1)头文件: #include <pthread.h>
定义一个线程:
pthread_t th;
ret = pthread_create(&th,NULL,thread,&arg);
&th : 线程描述符
thread :线程要执行的东西
注:Linux编译时可以链接多个库
例如:gcc snake.c -lcurses -lpthread
附完整程序,可直接在Linux中运行,程序中有注释。
/*
* 贪吃蛇游戏:(个别程序会被覆盖)
* 1、贪吃蛇地图:snake_map.c
* 地图边界:行x列 20x25
* 2、贪吃蛇身体1:snake_body.c
* 静态的获得一个身体
* 3、贪吃蛇身体2:snake_body2.c
* 静态的获得三个身体
* 4、贪吃蛇身体3:snake_body3.c
* 动态的创建贪吃蛇的身体
* 5、贪吃蛇方向:snake_dire.c
* 贪吃蛇向右移动(按一次动一次)
* 6、贪吃蛇撞墙:snake_dire2.c
* 贪吃蛇撞墙之后,游戏初始化
* 7、贪吃蛇自由行走:snake_dire3.c
* 无需按键,自己向右游走
* 8、贪吃蛇四个方向自由行走:snake_dire4.c
* 按下按键蛇根据按键方向自由行走
* 9、贪吃蛇行走问题:snake_dire5.c
* 绝对值方式解决贪吃蛇不合理走为问题
* 10、贪吃蛇吃食物:snake_food.c
* 贪吃蛇通过吃食物变长
* 11、贪吃蛇食物随机出现:snake_food2.c
* 贪吃蛇通过吃食物变长(控制食物不会超出地图边界并且地图内一直有食物存在)
* 12、贪吃蛇要咬死自己:snake_food3.c
* 当蛇头与蛇尾重合时,游戏重新开始
* 13、贪吃蛇的开始界面:snake_start_screen.c
*/
#include <curses.h>
#include <malloc.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#define UP 1
#define DOWN -1
#define RIGHT 2
#define LEFT -2
/*
* 函数声明部分:
*/
void InitNcurses();
void snakeMap();
int TravSnakeBody();
void snakebody();
void Addsnake();
void Initsnake();
void Deletsnake();
void movesnake();
void *refreshSnake();
void *changeDire();
void turn(int direction);
void Initfood();
int hasfood(int line,int list);
int ifsnakedie();
/*
* 结构体
*/
struct Snake
{
int line; //行
int list; //列
struct Snake *next;
};
/*
* 创建贪吃蛇的身体:(创建链表头和尾)
* 行一致,列加1
*/
struct Snake *head = NULL;
struct Snake *tail = NULL;
struct Snake food;
int key;
int dire; //方向
/*
初始化Ncurses函数:
*/
void InitNcurses()
{
initscr();
keypad(stdscr,1);
noecho(); //不显示按键的符号
}
/*
贪吃蛇地图:
四角的坐标:(行:列)
左上:(1:1) 右上:(1:24)
左下:(18,1) 右下: (18:24)
*/
void snakeMap()
{
int line; //行
int list; //列
for(line=0;line<20;line++)
{
if(line==0 || line==19) //--打印
{
for(list=0;list<25;list++)
{
printw("--");
}
}
else
{
for(list=0;list<26;list++) // ||打印及游戏界面
{
if(list==0 || list==25)
{
printw("|");
}
else
{
if(TravSnakeBody(line,list))
{
printw("[]");
}
else if(hasfood(line,list))
{
printw("##");
}
else{
printw(" ");
}
}
}
}
printw("\n");
}
printw("Key num:%d\n",key);
printw("Food line:%d\n",food.line);
printw("Food list:%d\n",food.list);
}
/*
* 遍历蛇身体:
*/
int TravSnakeBody(int line,int list)
{
struct Snake *point;
point = head;
while(point != NULL)
{
if(point->line==line && point->list==list)
{
return 1;
}
point = point->next;
}
return 0;
}
/*
* 创建贪吃蛇的身体:
* 刷新贪吃蛇地图
*/
void snakebody()
{
struct Snake *point;
point = head;
while(point->next != NULL)
{
move(0,0);
snakeMap();
point = point->next;
}
}
/*
* 初始化贪吃蛇:
* 作用:用尾插法创建一个链表
* */
void Initsnake() //初始化贪吃蛇
{
struct Snake *point;
dire = RIGHT;
while(head != NULL)
{
point = head;
head = head->next;
free(point);
}
Initfood();
head = (struct Snake *)malloc(sizeof(struct Snake));
head->line = 1;
head->list = 1;
head->next = NULL;
tail = head;
Addsnake();
Addsnake();
}
/*
* 增加贪吃蛇长度:
* 作用:为链表增加节点(每调用一次增加一个节点)
*/
void Addsnake()
{
struct Snake *new_snake = NULL;
new_snake = (struct Snake *)malloc(sizeof(struct Snake));
switch(dire)
{
case UP:{
new_snake->line = tail->line - 1;
new_snake->list = tail->list;
}break;
case DOWN:{
new_snake->line = tail->line + 1;
new_snake->list = tail->list;
}break;
case RIGHT:{
new_snake->line = tail->line;
new_snake->list = tail->list + 1;
}break;
case LEFT:{
new_snake->line = tail->line;
new_snake->list = tail->list - 1;
}break;
}
tail->next = new_snake;
tail = new_snake;
}
/*
* 删除链表一个节点(删除头节点)
*/
void Deletsnake()
{
struct Snake *point;
point = head;
head = head->next;
free(point);
}
/*
* 贪吃蛇的移动函数
*/
void movesnake()
{
Addsnake();
if(hasfood(tail->line,tail->list))
{
Initfood();
}
else
{
Deletsnake();
}
if(ifsnakedie())
{
Initsnake();
}
}
/*
* 转换函数:
* 用绝对值方法解决蛇走位不合理的问题 */
void turn(int direction)
{
if(abs(dire) != abs( direction))
{
dire = direction;
}
}
/*
* 贪吃蛇按键:(方向选择)
* 实现贪吃蛇的上下左右移动
*/
void *changeDire()
{
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;
}
}
}
/*
* 刷新游戏界面
*/
void *refreshSnake()
{
while(1)
{
move(0,0);
movesnake();
snakeMap();
usleep(100000);
refresh(); //刷新
}
}
/*
* 贪吃蛇食物:
* 食物:#
*/
void Initfood()
{
//xrand();是一个函数(随即生成一个数)
int x;
int y;
x = rand()%20; //地图中食物的坐标
y = rand()%20;
while(x==0 || y==0)
{
x = rand()%20;
y = rand()%20;
}
food.line = x;
food.list = y;
}
/*
* 确定贪吃蛇食物的位置
*/
int hasfood(int line,int list)
{
if(food.line == line && food.list == list)
{
return 1;
}
return 0;
}
/*
* 贪吃蛇复位(游戏重新开始)
* 贪吃蛇头与贪吃蛇尾巴重合时,游戏冲重新开始。
*/
int ifsnakedie()
{
struct Snake *point;
point = head;
if(tail->line==0 || tail->line==19|| tail->list==0 || tail->list == 25) //设置贪吃蛇撞墙参数
{
return 1;
}
while(point->next != NULL)
{
if(point->line == tail->line && point->list == tail->list)
{
return 1;
}
point = point->next;
}
return 0;
}
int main()
{
pthread_t th1;
pthread_t th2;
InitNcurses();
snakeMap();
Initsnake();
snakebody();
pthread_create(&th1,NULL,refreshSnake,NULL);
pthread_create(&th2,NULL,changeDire,NULL);
while(1); //主线程(防止程序退出)
getch(); //防止程序退出
endwin();
return 0;
}