基于Linux下Ncurses库的游戏开发

目录

一. 项目名称

二. 项目需要实现的功能

三. 根据项目的功能要求的具体实现思路

 四. Ncurses库的知识补充

1. Ncurses库介绍

2. Ncueses库安装

3. 项目需要用到的Ncurses库中的API

五. 实现项目功能代码思路

六.项目源码

七. 效果图


一. 项目名称

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;
	}
	
}

七. 效果图

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@daiwei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值