目录
一. 项目名称
Flappy Bird
二. 项目需要实现的功能
(1)按下空格键小鸟上升,不按小鸟下落
(2)搭建小鸟需要穿过的管道
(3)管道自动左移和创建
(4)小鸟撞到管道游戏结束
三. 根据项目的功能要求的具体实现思路
四. Ncurses库的知识补充
1. Ncurses库介绍
Ncurses是最早的System V Release 4.0 (SVr4)中 curses的一个克隆和升级。这是一个可自由配置的库,完全兼容旧版本curses。Ncurses构成了一个工作在底层终端代码之上的封装,并向用户提供了一个灵活高效的API(Application ProgrammingInterface 应用程序接口)。它提供了创建窗口界面,移动光标,产生颜色,处理键盘按键等功能。使程序员编写应用程序不需要关心那些底层的终端操作。简而言之,它是一个管理应用程序在字符终端显示的函数库。
2. Ncueses库安装
安装命令:sudo apt-get install libncurses5-dev
注:为了能够使用Ncurses库,必须在源程序中将#include<curses.h>包括进来,而且在编译的需要与它链接起来. 在gcc中可以使用参数-lncurses进行编译.
3. 项目需要用到的Ncurses库中的API
(1). initscr(void);
是curses模式的入口。将终端屏幕初始化为curses模式,为当前屏幕和相关的数据结构分配内存。
(2). int endwin(void);
是curses模式的出口,退出curses模式,释放curses子系统和相关数据结构占用的内存。
(3). int curs_set(int visibility);
设置光标是否可见,visibility:0(不可见),1(可见)
(4). int move(int new_y, int new_x);
将光标移动到new_y所指定的行和new_x所指定的列
(5). int addch(const chtype char);
在当前光标位置添加字符
(6). int refresh(void);
刷新物理屏幕。将获取的内容显示到显示器上。
(7). int keypad(WINDOW *window_ptr, bool key_on);
允许使用功能键。exp:keypad(stdscr,1);//允许使用功能按键
F1, F2键盘上的功能按键
(8). int getch(void);
读取键盘输入的一个字符
( 9). chtype inch(void);
获取当前光标位置的字符。
注:curses有自己的字符类型chtype,使用时强制类型转换为char
(10). int start_color(void);
启动color机制,初始化当前终端支持的所有颜色
(11). int init_pair(short pair_number, short foreground, short background);
配置颜色对
COLOR_BLACK 黑色 COLOR_MAGENTA 品红色magenta
COLOR_RED 红色 COLOR_CYAN 青色cyan
COLOR_GREEN 绿色 COLOR_WHITE 白色
COLOR_YELLOW 黄色 COLOR_BLUE 蓝色
(12). int COLOR_PAIR(int pair_number);
设置颜色属性,设置完颜色对,可以通过COLOR_PAIR实现
(13). int attron(chtype attribute);
启用属性设置
(14). int attroff(chtype attribute);
关闭属性设置
(15).noecho 禁止我们用户输入的字符显示
五. 实现项目功能代码思路
六.项目源码
#include <stdio.h>
#include <curses.h> //编译时加上-lncurses
#include <sys/time.h>
#include <signal.h>
#include <stdlib.h>
#define BIRD '@' //小鸟
#define BLANK ' ' //空白显示
#define PIPE '+' //管道
int x, y; //定义小鸟坐标
typedef struct Pipe { //定义管道信息
int x;
int y;
struct Pipe *next;
}Pipe_node, *Pipe_list;
Pipe_list head, tail; //定义链表的头尾节点
/*初始化相关工作*/
void Init_Curses(); //初始化ncurses库
int Set_Timer(int ms); //set timer
void Catch_Signal(); //捕捉信号函数
/*小鸟*/
void Bird_Show();
void Bird_Clear();
void Bird_move();
/*管道*/
void Pipe_Create(); //list create
void Pipe_Show(); //显示管道
void Pipe_Clear(); //管道清楚
void Pipe_Move(); //管道移动
int main(int argc, const char *argv[])
{
y = 10, x = 15; //小鸟的初始位置
srand(time(0)); //给一个随机种子
Init_Curses();
Catch_Signal();
set_timer(500);
Pipe_Create();
Pipe_Show();
Bird_Show();
Bird_move();
return 0;
}
/*初始化ncurses库*/
void Init_Curses() {
initscr(); //进入ncurses模式
curs_set(0); //禁止光标显示
keypad(stdscr, 1); //允许使用功能按键
start_color(); //启用颜色机制
noecho(); //禁止输入的字符显示
init_pair(1, COLOR_WHITE, COLOR_RED); //初始化颜色对
init_pair(2, COLOR_WHITE, COLOR_GREEN);
}
/*设置定时器时间*/
int set_timer(int ms) {
struct itimerval timer;
long t_sec, t_usec;
int ret;
t_sec = ms / 1000; // s
t_usec = (ms % 1000) * 1000; // us
timer.it_value.tv_sec= t_sec; //第一次启动的时间
timer.it_value.tv_usec = t_usec;
timer.it_interval.tv_sec = t_sec; //之后每隔多少时间启动一次
timer.it_interval.tv_usec = t_usec;
ret = setitimer(ITIMER_REAL, &timer, NULL); //setitimer函数启动定时
return ret;
}
/*信号是一种软中断*/
void handler(int sig) {
int i, j;
Pipe_list p, new;
Bird_Clear();
y++;
Bird_Show();
if((char)inch() == PIPE) {
set_timer(0);
endwin();
printf("Game over.\n");
exit(0);
}
p = head->next;
if(p->x == 0) {
head->next = p->next;
for(i = p->x; i < p->x + 10; i++) {
for(j = 0; j < p->y; j++) {
move(j, i);
addch(BLANK);
}
for(j = p->y + 5; j < 25; j++) {
move(j, i);
addch(BLANK);
}
refresh();
}
free(p);
new = (Pipe_list)malloc(sizeof(Pipe_node));
new->x = tail->x + 20;
new->y = rand() % 11 + 5;
new->next = NULL;
tail->next = new;
tail = new;
}
Pipe_Clear();
Pipe_Move();
Pipe_Show();
}
void Catch_Signal() {
struct sigaction sig;
sig.sa_handler = handler;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
sigaction(SIGALRM, &sig, NULL); //调用sigaction函数捕捉信号SIGALRM
/*
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
*/
}
/*小鸟显示*/
void Bird_Show() {
attron(COLOR_PAIR(1));
move(y, x);
addch(BIRD);
refresh();
attroff(COLOR_PAIR(1));
}
/*小鸟清除*/
void Bird_Clear() {
move(y, x);
addch(BLANK);
refresh();
}
/*小鸟移动*/
void Bird_move() {
char key;
while(1) {
key = getch();
if(key == ' ') {
Bird_Clear();
y--;
Bird_Show();
if((char)inch() == PIPE) { //游戏结束标志判断
set_timer(0);
endwin();
printf("Game over.\n");
exit(0);
}
}
/*
if(key = 'q') {
set_timer(0);
endwin();
printf("Quit!\n");
exit(0);
}
*/
}
}
/*链表的创建*/
void Pipe_Create() {
Pipe_list p, q;
int i;
p = (Pipe_list)malloc(sizeof(Pipe_node));
p->next = NULL;
head = p;
for(i = 0; i < 5; i++) {
q = (Pipe_list)malloc(sizeof(Pipe_node));
q->x = (i + 1) * 20; //列宽为20
q->y = rand() % 11 + 5; //行的值为随机值, 增加可玩性
q->next = NULL;
p->next = q;
p = p->next;
}
tail = p;
}
/*管道的显示*/
void Pipe_Show() {
Pipe_list p;
int i, j;
p = head->next;
attron(COLOR_PAIR(2));
while(p != NULL) {
for(i = p->x; i < p->x + 10; i++) {
for(j = 0; j < p->y; j++) {
move(j, i);
addch(PIPE);
}
for(j = p->y + 5; j < 25; j++) {
move(j, i);
addch(PIPE);
}
}
refresh();
p = p->next; //移动到下一个节点, 准备显示下一个管道
}
attroff(COLOR_PAIR(2));
}
/*管道的清除*/
void Pipe_Clear() {
Pipe_list p;
int i, j;
p = head->next;
while(p != NULL) {
for(i = p->x; i < p->x + 10; i++) {
for(j = 0; j < p->y; j++) {
move(j, i);
addch(BLANK);
}
for(j = p->y + 5; j < 25; j++) {
move(j, i);
addch(BLANK);
}
}
refresh();
p = p->next;
}
}
/*管道的移动*/
void Pipe_Move() {
Pipe_list p;
p = head->next;
while(p != NULL) {
p->x--;
p = p->next;
}
}
七. 效果图