Linux实现Flappy bird项目

目录

1、项目介绍

2、功能总结

3、前期准备

3.1 Ncurses库 

3.2 信号机制 

3.2.1 设置信号响应方式

3.2.2 设置定时器 

4、代码实现 

4.1 头文件引用及变量、函数定义

4.2 主函数

4.3 curses初始化 

4.4 设置定时器

4.5 定时器响应函数 

4.6 小鸟控制相关函数

4.7 管道控制相关函数 

5、效果测试


1、项目介绍

flappy bird是一款来自越南的独立游戏开发者Dong Nguyen所开发的作品游戏中玩家必须控制一只小鸟,跨越由各种不同长度水管所组成的障碍。

2、功能总结

  1. 按下空格键小鸟上升,不按小鸟下落
  2. 搭建小鸟需要穿过的管道
  3. 管道自动左移和创建
  4. 小鸟撞到管道游戏结束

3、前期准备

3.1 Ncurses库 

做这个项目之前,有两个值得思考:

  1. 如何显示游戏界面?
  2. 如何实现空格键控制小鸟上升?

我们可以通过Ncurses库来实现

Ncurses是最早的System V Release 4.0 (SVr4)中 curses的一个克隆和升级。

这是一个可自由配置的库,完全兼容旧版本curses。Ncurses构成了一个工作在底层终端代码之上的封装,并向用户提供了一个灵活高效的API(Application Programming Interface 应用程序接口)。它提供了创建窗口界面,移动光标,产生颜色,处理键盘按键等功能。使程序员编写应用程序不需要关心那些底层的终端操作。

简而言之,它是一个管理应用程序在字符终端显示的函数库。 

安装命令:

sudo apt-get install libncurses5-dev

注:为了能够使用Ncurses库,必须在源程序中将#include<curses.h>包括进来,而且在编译的需要与它链接起来. 在gcc中可以使用参数-lncurses进行编译.

initscr(void);是curses模式的入口。将终端屏幕初始化为curses模式,为当前屏幕和相关的数据结构分配内存。
int  endwin(void); 是curses模式的出口,退出curses模式,释放curses子系统和相关数据结构占用的内存。
int curs_set(int visibility); 设置光标是否可见,visibility:0(不可见),1(可见)
int move(int  new_y, int  new_x);将光标移动到new_y所指定的行和new_x所指定的列
int addch(const  chtype  char); 在当前光标位置添加字符
int  refresh(void); 刷新物理屏幕。将获取的内容显示到显示器上。    
int  keypad(WINDOW  *window_ptr,  bool  key_on); 允许使用功能键。exp:keypad(stdscr,1);//允许使用功能按键
 int getch(void);  读取键盘输入的一个字符
chtype inch(void); 获取当前光标位置的字符。
    注:curses有自己的字符类型chtype,使用时强制类型转换为char
int start_color(void); 启动color机制,初始化当前终端支持的所有颜色
int init_pair(short  pair_number,  short  foreground,  short  background);配置颜色对        
    COLOR_BLACK         黑色        COLOR_MAGENTA      品红色
    COLOR_RED           红色        COLOR_CYAN          青色
    COLOR_GREEN         绿色        COLOR_WHITE      白色
    COLOR_YELLOW     黄色       COLOR_BLUE       蓝色
int  COLOR_PAIR(int  pair_number); 
 
 设置颜色属性,设置完颜色对,可以通过COLOR_PAIR实现
int  attron(chtype  attribute); 启用属性设置
int  attroff(chtype  attribute); 关闭属性设置

示例:

#include <stdio.h>
#include <curses.h>

int main(int argc,const char* argv[])
{
	char ch;
	initscr();//进入curses模式
	curs_set(0);
	keypad(stdscr,1);//允许使用功能按键
	noecho();//禁止输入字符显示
	start_color();//启动颜色机制
	init_pair(1,COLOR_RED,COLOR_BLUE);

	attron(COLOR_PAIR(1));
	move(10,10);
	addch('@');
	refresh();
	attroff(COLOR_PAIR(1));
	while(1);
	endwin();//退出curses模式
	return 0;
}

3.2 信号机制 

获取空格按键是可以通过getchar阻塞获取字符按键输入,但是这样做就会影响小鸟的下落和管道的创建。在Linux中,软中断信号(signal,简称为信号)是在软件层次上对中断的一种模拟,用来通知进程发生了异步事件。内核可以因为内部事件而给进程发送信号,通知进程发生了某个事件。

信号响应的方式:

  • 忽略信号,即对信号不做任何处理;
  • 捕捉信号,即信号发生时执行用户自定义的信号处理函数。
  • 执行缺省操作,Linux对每种信号都规定了默认操作。

3.2.1 设置信号响应方式

#include  <unistd.h>
#include <signal.h>

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler); 

 成功时返回原先的信号处理函数,失败时返回SIG_ERR

  • signum:指明了所要处理的信号类型
  • handler:描述了与信号关联的动作,SIG_DFL代表缺省方式; SIG_IGN 代表忽略信号;指定的信号处理函数代表捕捉方式

示例 

// 头文件省略
void handler (int signo) {
    printf(“HELLO!\n”); 
}

int  main() {
    signal(SIGINT, handler);
    while ( 1 ) ;
    return 0;
}

3.2.2 设置定时器 

struct itimerval {
    struct timeval it_interval; /* 计时器重新启动的间歇值 */
    struct timeval it_value;    /* 计时器安装后首次启动的初 };                               始值,之后就没有用 */
struct timeval {
    long tv_sec;       /* 秒 */
    long tv_usec;      /* 微妙*/
};
int setitimer(int which, const struct itimerval *value,
              struct itimerval *ovalue)

参数:

  • which:间歇计时器类型,ITIMER_REAL      //数值为0,发送的信号是SIGALRM。
  • struct itimerval *value:将value指向的结构体设为计时器的当前值;
  • struct itimerval *ovalue:保存计时器原有值。一般设置为NULL。

返回值: 成功返回0。失败返回-1。 

4、代码实现 

4.1 头文件引用及变量、函数定义

#include <stdio.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#include <stdlib.h>

#define BIRD '@'
#define BLANK ' '
#define PIPE '+'
/*定义关于管道的结构体*/
typedef struct Pipe{
	int x;//列坐标
	int y;//横坐标
	struct Pipe *next;
}Pipe_node, *Pipe_list;

Pipe_list head,tail;

void creat_list();//创建链表
void show_pipe();//显示管道
void clear_pipe();//清楚管道
void move_pipe();//移动管道

int bird_y,bird_x;//小鸟坐标

void show_bird();//显示小鸟
void clear_bird();//清除小鸟
void move_bird();//移动小鸟

void init_curses();//curses库初始化
int set_timer(int ms_t);//设置定时器--ms
void handler(int sig);//信号处理函数

4.2 主函数

int main()
{
	bird_y = 15;//行
	bird_x = 10;//列
	init_curses();
	signal(SIGALRM,handler);
	set_timer(500);//500ms

	srand(time(0));//随机种子
	creat_list();
	show_pipe();
	show_bird();
	move_bird();
	return 0;
}

4.3 curses初始化 

void init_curses()
{
	initscr();//进入curses模式
	curs_set(0);//禁止光标显示
	noecho();//禁止输入字符显示
	keypad(stdscr,1);//启动功能按键
	start_color();//启动颜色机制
	init_pair(1,COLOR_WHITE,COLOR_RED);//小鸟颜色设置
	init_pair(2,COLOR_WHITE,COLOR_GREEN);//管道颜色设置
}

4.4 设置定时器


int set_timer(int ms_t)
{
	struct itimerval timer;
	long t_sec,t_usec;
	int ret;

	t_sec = ms_t / 1000;//s
	t_usec = (ms_t % 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);//

	return ret;

}

4.5 定时器响应函数 

void handler(int sig)
{
	Pipe_list p,new;
	//小鸟下落
	clear_bird();
	bird_y++;
	show_bird();
	/*游戏结束判断*/
	if((char)inch() == PIPE)
	{
		set_timer(0);
		endwin();
		exit(1);
	}

	p = head->next;
	int i,j;
	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;
	}
	//管道移动
	clear_pipe();
	move_pipe();
	show_pipe();
}

4.6 小鸟控制相关函数

void show_bird()//显示小鸟
{
	attron(COLOR_PAIR(1));
	move(bird_y,bird_x);
	addch(BIRD);
	refresh();
	attroff(COLOR_PAIR(1));
}
void clear_bird()//清除小鸟
{
	move(bird_y,bird_x);
	addch(BLANK);
	refresh();

}
void move_bird()//移动小鸟
{
	char key;
	while(1)
	{
		key = getch();
		if(key == ' ')
		{
			clear_bird();
			bird_y--;
			show_bird();
			/*游戏结束判断*/
			if((char)inch() == PIPE)
			{
				set_timer(0);
				endwin();
				exit(1);
			}
		}
	}
}

4.7 管道控制相关函数 

void creat_list()//创建链表
{
	int i;

	Pipe_list p,new;
	head = (Pipe_list)malloc(sizeof(Pipe_node));
	head->next = NULL;
	p = head;
	
	for(i = 0;i<5;i++)
	{
		new = (Pipe_list)malloc(sizeof(Pipe_node));
		new->x = (i+1)*20;
		new->y = rand()%11+5;//(5-15行)
		new->next = NULL;
		p->next = new;
		p = new;
	}
	tail = p;
}
void show_pipe()//显示管道
{
	Pipe_list p;
	int i,j;
	p = head->next;
	attron(COLOR_PAIR(2));
	while(p)
	{
		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 clear_pipe()//清除管道
{
	Pipe_list p;
	int i,j;
	p = head->next;
	while(p)
	{
		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 move_pipe()//移动管道
{
	Pipe_list p;
	p = head->next;
	while(p)
	{
		p->x--;
		p = p->next;
	}
}

5、效果测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/599879.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java的Fork-Join简单介绍

Java的Fork-Join框架是Java 7引入的一个用于并行处理的轻量级框架&#xff0c;它基于分治策略&#xff08;Divide and Conquer&#xff09;&#xff0c;特别适合于那些可以被分解为多个子任务的任务。Fork-Join框架的核心思想是将一个大任务&#xff08;Task&#xff09;拆分成…

毕业就业信息|基于Springboot+vue的毕业就业信息管理系统的设计与实现(源码+数据库+文档)

毕业就业信息管理系统 目录 基于Springboot&#xff0b;vue的毕业就业信息管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 1学生信息管理 2 公司信息管理 3公告类型管理 4公告信息管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设…

高等数学笔记(下中)

曲线积分 第一类曲线积分&#xff1a;对弧长的积分计算方法 定理&#xff1a;设 f ( x , y ) f(x,y) f(x,y)在曲线弧 L L L上有定义且连续&#xff0c; L L L的参数方程是 { x φ ( t ) y ψ ( t ) ( α ≤ t ≤ β ) \begin{cases} x\varphi(t)\\ y\psi(t) \end{cases}(\a…

Python实现打砖块游戏

提供学习或者毕业设计使用&#xff0c;功能基本都有&#xff0c;不能和市场上正式游戏相提比论&#xff0c;请理性对待&#xff01; 在本文中&#xff0c;我们将使用 Pygame 和 Tkinter 创建一个简单的打砖块游戏。游戏的目标是通过控制挡板来击碎屏幕上的砖块&#xff0c;同时…

PTQ4SAM、Mamba-Attention、AniTalker、IceFormer、U-DiTs、CogDPM

本文首发于公众号&#xff1a;机器感知 PTQ4SAM、Mamba-Attention、AniTalker、IceFormer、U-DiTs、CogDPM PTQ4SAM: Post-Training Quantization for Segment Anything Segment Anything Model (SAM) has achieved impressive performance in many computer vision tasks. Ho…

华为机考入门python3--(23)牛客23- 删除字符串中出现次数最少的字符

分类&#xff1a;字符串 知识点&#xff1a; 访问字典中keychar的值&#xff0c;不存在则返回0 my_dict.get(char, 0) 字典的所有值 my_dict.value() 列表中的最小值 min(my_list) 题目来自【牛客】 import sysdef delete_min_freq_char(s):# 计算字母出现的频次…

套管外径测量仪 多尺寸型号 规格全可定制

套管&#xff08;bushing&#xff09;是一种将带电导体引入电气设备或穿过墙壁的一种绝缘装置。前者称为电器套管&#xff0c;后者称为穿墙套管。套管通常用在建筑地下室&#xff0c;是用来保护管道或者方便管道安装的铁圈。套管的分类有刚性套管、柔性防水套管、钢管套管及铁皮…

鸿蒙OpenHarmony实战开发-MiniCanvas

介绍 基于OpenHarmony的Cavas组件封装了一版极简操作的MiniCanvas&#xff0c;屏蔽了原有Canvas内部复杂的调用流程&#xff0c;支持一个API就可以实现相应的绘制能力&#xff0c;该库还在继续完善中&#xff0c;也欢迎PR。 使用说明 1.添加MiniCanvas依赖 在项目entry目录…

07 - 步骤 javaScript代码

简介 JavaScript 代码是通过 JavaScript 脚本步骤来执行 JavaScript 脚本的一种方式。这允许用户在 Kettle 的数据流程中使用 JavaScript 编写自定义的脚本逻辑&#xff0c;用于数据处理、转换、计算等操作。 使用 场景 我需要在数据流加一个字段 createTime 当前时间&…

【嵌入式DIY实例】-基于GSM的远程灌溉系统

基于GSM的远程灌溉系统 文章目录 基于GSM的远程灌溉系统1、硬件准备与接线2、软件准备3、代码实现本文将详细介绍如何搭建通过使用手机实现对灌溉系统的远程控制。该系统利用全球移动通信系统(GSM)技术在灌溉系统和移动电话之间建立通信。该系统建立在流行的开源微控制器平台…

Linux 进程间通信之共享内存

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux知识分享⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多Linux知识   &#x1f51d; ​ 目录 ​编辑​ 前言 共享内存直接原理…

使用双指针解决问题题集(二)

1. 有效三角形的个数 给定一个包含非负整数的数组 nums &#xff0c;返回其中可以组成三角形三条边的三元组个数。 示例 1: 输入: nums [2,2,3,4] 输出: 3 解释:有效的组合是: 2,3,4 (使用第一个 2) 2,3,4 (使用第二个 2) 2,2,3 示例 2: 输入: nums [4,2,3,4] 输出: 4 题解&a…

zabbix监控方式(zabbix-trapper)

中文&#xff1a;zabbix采集器&#xff0c;即zabbix sender 。 Zabbix-Trapper 监控方式可以一次批量发送数据给Zabbix Server&#xff0c;与主动模式不同&#xff0c;Zabbix-Trapper 可以让用户控制数据的发送&#xff0c;而不用Zabbix-Agent进程控制&#xff0c;这意味着可以…

Angular中的管道(Pipe)

Angular中的管道(Pipe) 文章目录 Angular中的管道(Pipe)前言一、内置管道1. date管道格式化日期2. currency管道格式化货币3. uppercase和lowercase管道转换字符串大小写4. 小数位数5. JavaScript 对象序列化6. slice7. 管道链 二、自定义管道 前言 Angular中的管道&#xff0…

力扣刷题--数组--第二天

今天仍然做二分查找相关的题目。先来回顾一下二分查找的方法和使用的条件。二分查找是在数组中查找目标值的一种方法&#xff0c;通过边界索引确定中间索引&#xff0c;判断中间索引处的元素值和目标值的大小&#xff0c;来不断缩小查找区间。使用二分查找有如下一些限制&#…

ASP.NET通用作业批改系统设计

摘  要 该系统采用B/S结构&#xff0c;以浏览器方式登陆系统&#xff0c;用ASP.NET作为开发语言&#xff0c;数据库则使用Microsoft SQL Server 2000实现。《通用作业批改系统》包括了学生子系统、教师子系统、管理员子系统三大模块&#xff0c;该系统主要完成学生&#xff…

LibTorch入坑记--续2

一、安装faiss 我的faiss&#xff0c;用的是曾经安装过的 pip install faiss-gpu1.7 当时搞得环境名称是pni 二、配置环境 三、例子代码 #include <faiss/IndexFlat.h> #include <faiss/Index.h> #include <faiss/VectorTransform.h> #include <faiss/…

Mybatis进阶4-权限管理

权限管理 1.权限 //相当于 职责 2.用户 //相当于 职员&#xff08;职员就职于一个职位&#xff09; 3.角色 //相当于 职位&#xff08;有多个职责&#xff09; 权限管理基础表&#xff1a;权限表&#xff0c;用户表&#xff0c;角色表 问题1&#xff1a;…

SVM直观理解

https://tangshusen.me/2018/10/27/SVM/ https://www.bilibili.com/video/BV16T4y1y7qj/?spm_id_from333.337.search-card.all.click&vd_source8272bd48fee17396a4a1746c256ab0ae SVM是什么? 先来看看维基百科上对SVM的定义: 支持向量机&#xff08;英语&#xff1a;su…

根据最近拒包项目总结,详细讲解Google最新政策(上)

关于占比最多的移动垃圾软件拒审问题 移动垃圾软件(Mobile Unwanted Software)特征表现1> 具有欺骗性,承诺其无法实现的价值主张。2> 诱骗用户进行安装,或搭载在用户安装的其他程序上。3> 不向用户告知其所有主要功能和重要功能。4> 以非预期方式影响用户的系统…
最新文章