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、功能总结
- 按下空格键小鸟上升,不按小鸟下落
- 搭建小鸟需要穿过的管道
- 管道自动左移和创建
- 小鸟撞到管道游戏结束
3、前期准备
3.1 Ncurses库
做这个项目之前,有两个值得思考:
- 如何显示游戏界面?
- 如何实现空格键控制小鸟上升?
我们可以通过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);//500mssrand(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;//st_usec = (ms_t % 1000)*1000;//ustimer.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、效果测试
相关文章:

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…...

【python量化交易】qteasy使用教程07——创建更加复杂的自定义交易策略
创建更加复杂的自定义交易策略 使用交易策略类,创建更复杂的自定义策略开始前的准备工作本节的目标继承Strategy类,创建一个复杂的多因子选股策略策略和回测参数配置,并开始回测 本节回顾 使用交易策略类,创建更复杂的自定义策略 …...

SpringBoot整合SpringScurity权限控制(菜单权限,按钮权限)以及加上SSH实现安全传输
文章目录 项目地址: 一、md5 与 先进的哈希算法的区别1.1. 安全性问题1.2. 设计目的1.3. 功能特性1.4. 适用性1.5. 总结 二、数据传输安全和数据加密实现:2.1 生成证书:2.2、在springboot中进行集成2.2.1 配置证书:2.2.2. 强制使用…...

力扣每日一题119:杨辉三角||
题目 简单 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1]示例 2: 输入: rowIndex 0 输出: [1]示例 3: 输入: rowIndex 1 输出…...

AI语音模型PaddleSpeech踩坑(安装)指南
PaddleSpeech简介 PaddleSpeech 是基于飞桨 PaddlePaddle 的语音方向的开源模型库,用于语音和音频中的各种关键任务的开发,包含大量基于深度学习前沿和有影响力的模型。 PaddleSpeech安装步骤 提示:要找到一个合适的PaddleSpeech版本与pad…...

如何更好地使用Kafka? - 运行监控篇
要确保Kafka在使用过程中的稳定性,需要从kafka在业务中的使用周期进行依次保障。主要可以分为:事先预防(通过规范的使用、开发,预防问题产生)、运行时监控(保障集群稳定,出问题能及时发现&#…...

数据可视化训练第四天(模拟投掷筛子并且统计频次)
投掷一个筛子 import matplotlib.pyplot as plt from random import randint import numpy as npclass Die:"""模拟投掷筛子"""def __init__(self,num_sides6):self.num_sidesnum_sidesdef roll(self):return randint(1,self.num_sides)num1000…...

4.1 编写程序,从键盘接收一个小写字母,然后找出他的前导字符和后续字符,再按顺序显示这三个字符
方法一: 运行效果: 输入B,输出显示ABC;输入A,输出显示AB 思路: 1、通过键盘输入接收一个字母。 2、将输入的字母减去1,得到前导字符,然后输出。 3、将输入的字母加上1,得…...
(Java)心得:LeetCode——18.四数之和
一、原题 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): …...

网络编程套接字详解
目录 1. 预备介绍 2.网络字节序 3.udp网络程序 4.地址转换函数 5.udp网络编程 1.预备介绍 1.1源IP地址和目标IP地址 举个例子: 从北京出发到上海旅游, 那么源IP地址就是北京, 目标IP地址就是上海. 1.2 端口号 作用: 标识一个进程, 告诉OS这个数据交给那个进程来处理; (1)…...
蓝桥杯备战11.歌唱比赛
P5738 【深基7.例4】歌唱比赛 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> #define endl \n #define int long long using namespace std; const int N 2e710,M 1e310; int a[N],sum[N];signed main() {//std::ios::sync_with_stdio(0),cin.…...
微信小程序中的图像奥秘:图片与Base64的华丽变身记
微信小程序中的图像奥秘:图片与Base64的华丽变身记 基本概念解析图片与Base64的关系为何转换 图片转Base64实战微信小程序使用wx.getImageInfo获取图片信息图片转换为Base64注意 Base64转图片直接在小程序页面显示云开发环境转换注意 遇遇问题排查思路结语引发讨论 …...

【35分钟掌握金融风控策略25】定额策略实战2
目录 基于收入和负债的定额策略 确定托底额度和盖帽额度 确定基础额度 基于客户风险评级确定风险系数 计算最终授信额度 确定授信有效期 基于收入和负债的定额策略 在实际生产中,客户的收入和负债数据大多无法直接获得,对于个人的收入和负债数据&…...
我和爬虫的故事
文章目录 爬虫简介个人经历未来总结 爬虫简介 网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外…...

常用的简单友好的工单系统(免费)- WGCAT
最近在项目中,有工单系统的需求场景,所以想寻找一款轻量简单的运维工单软件,主要用来记录和处理工作中的一些故障、维护,主要用来记录设备的维护状态,包括服务器、主机、交换机那些 WGCAT,是一款简单轻量的…...

使用Pycharm编写Python程序时对基本类结构中方法的重写的两种初步操作方式
使用Pycharm编写Python程序时对基本类结构中方法的重写的两种初步操作方式 Python和其他一些高级面向对象的编程语言中,子类可继承父类中的方法,而不需要重新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想作一定的修改&…...
HTTP URL 详解
概述 URL 提供了一种定位因特网上任意资源的手段,大多数 URL 语法都由以下九个结构的通用格式组成: <scheme>://<user>:<password><host>:<port>/<path>;<params>?<query>#<frag> 方案&#…...
Python 原生爬虫
Python 描述代码 描述 爬网站的页面配合正则表达式设置定时任务 仅学习参考,切勿使用其他用途 代码 import re import schedule import timefrom urllib.request import urlopenclass Spider:def __init__(self):# 初始化代码...pass# self.start_schedule()# 需要…...

数据结构---经典链表OJ
乐观学习,乐观生活,才能不断前进啊!!! 我的主页:optimistic_chen 我的专栏:c语言 点击主页:optimistic_chen和专栏:c语言, 创作不易,大佬们点赞鼓…...
HTML_CSS学习:CSS像素与颜色
一、像素 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>像素</title> </head><style>.atguigu1{/*单位可以是cm,但不能是m,dm*/width: 1cm;height: 1cm;background-c…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
flow_controllers
关键点: 流控制器类型: 同步(Sync):发布操作会阻塞,直到数据被确认发送。异步(Async):发布操作非阻塞,数据发送由后台线程处理。纯同步(PureSync…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
比较数据迁移后MySQL数据库和ClickHouse数据仓库中的表
设计一个MySQL数据库和Clickhouse数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...