1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 基于Linux ncurses图形库的贪吃蛇小游戏

基于Linux ncurses图形库的贪吃蛇小游戏

时间:2019-12-30 14:18:25

相关推荐

基于Linux ncurses图形库的贪吃蛇小游戏

达者为先师者之意

基于Linux ncurses图形库的贪吃蛇小游戏

前言1 ncurses库程序的标准模式2 ncurses库的常用函数3 基于Linux ncurses图形库的贪吃蛇小游戏的完整代码

前言

为什么要用到ncurses库呢?

因为直接用 scanf 和 getchar 时,需要按下回车才能完成输入;

而贪吃蛇小项目用方向控制小蛇时,不可能按下方向键后还要按下回车;

所以我们需要ncurses库来完成对方向键的输入。

若Ubuntu没有安装ncurses库,则需要安装

执行命令

sudo apt-get install libncurses5-dev

即可安装

如下图所示

没按下回车,用 scanf 不能输入方向键。

#include <stdio.h>int main(){printf("------------------------------------\n");printf("|[][][] |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("| |\n");printf("------------------------------------\n");char i;scanf("%c",&i);return 0;}

1 ncurses库程序的标准模式

#include <ncurses.h> //要包含头文件#include <curses.h>int main(){initscr(); //初始化 进入curses模式.................. endwin(); //退出curses模式return 0;}

1.1 使用ncurses库 ,要包含头文件#include <curses.h>;(ncurses名字中的n意味着new,即是new curses,假如使用的是curses库, 要加的头文件则是 #include <curses.h>)

1.2 编译时要加上-lncurses ,如gcc a.c - lncurses,若想要生成自命名为abc的可执行文件,则编译时应为:gcc a.c - lncurses -o abc

1.3initscr();// 初始化,进入ncurses模式

1.4endwin();// 退出ncurses模式

2 ncurses库的常用函数

2.1 输入

getch();// 输入一个字符

getstr();// 输入一串字符串

scanw(“%s”,string);// 输入一串字符串

2.2 输出

addch();// 显示一个字符

addstr();// 显示一串字符串

printw(“%c”,变量);// 类似 printf 打印内容

refresh();//刷新物理屏幕

在我们使用 printw 时,实际上这个数据被打印到一个叫作“stdscr”的虚拟窗口上,没有被直接输出到屏幕上。printw()函数的作用是不断将一些显示标记和相关的数据结构写在虚拟显示器上,并将这些数据写入 stdscr 的缓冲区内。所以,为了显示这些缓冲区中的数据我们必须使用 refresh() 函数告诉 ncurses 系统将缓冲区的内容输出到屏幕上。这种机制可以不断在虚拟屏幕上写入数据,而调用 refresh() 函数时让一切看起来似乎是一次完成的。因为 refresh() 函数只核查窗口和数据中变动的部分,这种富有弹性的设计提供了一个高效的反馈机制。所以说不断在虚拟屏幕上写入数据时,我们应该在 printw函数后加上refresh函数,这样才能实现不断实时显示,而一次的静态显示,可以只用printw。

2.3 keypad(win,bf)

呼叫 keypad 时须传入两个值:

win为 WINDOW 型态指标,通常传入标准输出入屏幕stdscr,bf 为TRUE 或 FALSE

当开启 keypad 后, 可以使用键盘上的一些特殊字元, 如上下左右等方向键

curses 会将这些特殊字元转换成 curses.h 内定义的一些特殊键,这些定义的特殊键通常以 KEY_ 开头

2.4 睡眠时间函数

sleep();//以秒为单位

unsigned int sleep(unsigned int seconds);

头文件

#include<unistd.h>

sleep()非系统调用,sleep()是在库函数中实现的,它是通过alarm()来设定报警时间,使用sigsuspend()将进程挂起在信号SIGALARM上。

sleep()只能精确到秒级上。sleep()会令目前的进程暂停,直到达到参数seconds 所指定的时间,或是被信号所中断。

return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余秒数。

usleep(); //以微秒为单位

unsigned int usleep(unsigned int useconds);

除了时间单位为微秒以外,在使用上与sleep()差不多。还有就是实现也是不同的,sleep因为是用alarm实现的,所以时间单位为s ,而usleep的时间单位为us(微妙) ,那肯定不是由alarm实现的,所以说它们的实现不同,但都是linux用的,而window下不能用,因为都是sleep和usleep都是在unistd.h下定义的。

特别提醒:退出ncurses程序运行的操作界面,按Ctrl+c

3 基于Linux ncurses图形库的贪吃蛇小游戏的完整代码

#include <ncurses.h>#include <stdlib.h>#include <stdio.h>#include <pthread.h>#include <time.h>#include <unistd.h>//宏定义贪吃蛇上下左右移动的方向键#define UP1#define DOWN -1#define LEFT 2#define RIGHT -2struct Snack *head = NULL;//贪吃蛇的头节点struct Snack *tail = NULL;//贪吃蛇的尾节点int key;//键值int dir = 4; //初始化蛇移动的方向int score = 0;//成绩/*游戏布局界面用结构体来初始化*/struct Snack{int hang;int lie;struct Snack *next;};struct Snack food;//定义结构体foodvoid initFood(){int x = rand()%20;//随机生成数取余,随机刷新食物的位置int y = rand()%20;if(x >= 1 && x < 20 && y >= 1 && y < 20){food.hang = x;food.lie = y;}}//初始化按键操作void initNcurse(void){initscr();keypad(stdscr,1);noecho();}//判断随机生成食物的坐标与游戏框内的随机坐标int hasSnackFood(int i,int j){if(food.hang == i && food.lie == j){return 1; //相等返回1}return 0;}//头节点head初始化函数int hasSnackNode(int i,int j){struct Snack *p;p = head;while(p != NULL)//判断头节点是否指向NULL{if(p->hang == i && p->lie == j)//判断蛇的初始化坐标和hang,lie的坐标是否相等 {return 1;//为1,打印蛇身节点}p = p->next; //方便下一次循环判断是否为NULL}return 0; //节点为NULL,返回0}/*游戏界面设计用Ncurses图形库来做,定义gamePic函数初始化游戏界面*/void gamePic(void){int hang;int lie;move(0,0);//调用Ncurses图形库自带的move函数实现按键控制蛇的走位/*实现游戏界面的上下左右边框*/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(hasSnackNode(hang,lie)){printw("[]"); //打印蛇的身子}else if(hasSnackFood(hang,lie)){printw("##"); //随机刷新食物}else{printw(" "); //打印空格}}printw("\n");}if(hang == 19){for(lie=0;lie<20;lie++){printw("--"); //打印下边框}printw("\n");printw(" by MRDOCMAN,score = %d\n",score);}}}void addNode(){struct Snack *new;new = (struct Snack *)malloc(sizeof(struct Snack));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; //新加入的节点重新指向tail}void initSnack(){/*使用链表的尾插法,移动时*/struct Snack *p;dir = RIGHT;while(head != NULL){p = head;head = head->next;free(p);}initFood(); //刷新食物head = (struct Snack *)malloc(sizeof(struct Snack));head->hang = 2;head->lie = 2;head->next = NULL;tail = head;addNode();addNode();}//头节点删除,尾节点增加void deleNode(){struct Snack *p;p = head;head = head->next;free(p);}int ifSnackDie(){struct Snack *p;p = head;if(tail->hang<0 || tail->lie==0 || tail->hang==20 || tail->lie==20)//判断蛇是否撞墙{return 1;}while(p->next != NULL){if(p->hang == tail->hang && p->lie == tail->lie){return 1;}p = p->next;}return 0;}void moveSnack(){addNode();if(hasSnackFood(tail->hang,tail->lie)){initFood();score+=1;//食物重新刷新后,得分加一}else{deleNode();}if(ifSnackDie()){initSnack();score = 0; //撞墙后得分清零}}//刷新游戏界面void* refreshJieMian(){while(1){moveSnack();gamePic();refresh();usleep(100000);}}void turn(int direc){if(abs(dir) != abs(direc)){dir = direc;}}void* changeDir(){while(1){key = getch();switch(key){case KEY_RIGHT:turn(RIGHT);break;case KEY_LEFT:turn(LEFT);break;case KEY_DOWN:turn(DOWN);break;case KEY_UP:turn(UP);break;}}}int main(){pthread_t t1;pthread_t t2;initNcurse();initSnack();gamePic();pthread_create(&t1,NULL,refreshJieMian,NULL);pthread_create(&t2,NULL,changeDir,NULL);while(1);getch();endwin();return 0;}

码字不易求个三连

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。