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);//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、效果测试

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 自定义类型——联合体

目录: 一、联合体是&#xff1f;声明计算内存大小 二、联合体的特点例如 三、联合体大小的计算规则&#xff1a; 四、应用习1习2 一、联合体是&#xff1f; 联合体和结构体差不多&#xff0c;但是其最大的区别在于联合体所有的成员共用一块内存空间。所以联合体也叫共用体。联…

stm32f103c8t6最小系统板

STM32F103C8T6最小系统板是为基于ARM Cortex-M3内核的STM32F103C8T6微控制器设计的电路板&#xff0c;它包含了单片机正常运行所需的最基本组件。以下是构成STM32F103C8T6最小系统板的基本部分&#xff1a; 单片机芯片&#xff1a;STM32F103C8T6本身&#xff0c;它是一款32位微…

Java_方法引用

方法引用就是把已经有的方法拿过来用&#xff0c;当作函数式接口中抽象方法的方法体。 条件&#xff1a; 1.引用处需要是函数式接口 2.被引用的方法需要已经存在 3.被引用的方法的形参和返回值需要跟抽象方法的形参和返回值保持一致 4.被引用方法的功能需要满足当前的要求 简…

搭建父模块和工具子模块

第一章 项目父模块搭建 1.1 nancal-idsa 作为所有工程的父工程&#xff0c;用于管理项目的所有依赖版本。 1.2 指定 pom 类型模块&#xff0c;删除 src 目录&#xff0c;点击Reload project 1.3 添加依赖 pom.xml <parent> <groupId>org.springframework.…

Python爬虫教程:入门爬取网页数据

1.遵守法律法规 爬虫在获取网页数据时&#xff0c;需要遵守以下几点&#xff0c;以确保不违反法律法规&#xff1a; 不得侵犯网站的知识产权&#xff1a;爬虫不得未经授权&#xff0c;获取和复制网站的内容&#xff0c;这包括文本、图片、音频、视频等。 不得违反网站的使用条…

【华为机考模拟题】Words、Vowel、计算字符串重新排列数

目录 一、Words 二、Vowel 三、计算字符串重新排列数 一、Words 每个句子由多个单词组成&#xff0c;句子中的每个单词的长度都可能不一样&#xff0c;假设每个单词的长度 Ni 为该单词的重量&#xff0c;你需要做的就是给出整个句子的平均重量 V。 输入&#xff1a; Who L…

如何设置ddns动态域名服务实现外网访问

在本地搭建好服务器&#xff0c;部署好web网站或其他应用后&#xff0c;需要在外网访问内网时&#xff0c;如何设置动态域名服务ddns&#xff0c;将主机的内网IP端口映射到外网访问&#xff0c;是我们需要面对的一个重要步骤。 内网发布外网&#xff0c;常见的有两种方案&…

【智能优化算法】金枪鱼群优化(Tuna Swarm Optimization,TSO)

金枪鱼群优化&#xff08;Tuna Swarm Optimization,TSO&#xff09;是期刊“Computational Intelligence and Neuroscience”&#xff08;IF&#xff1a;1.8&#xff09;的2021年智能优化算法 01.引言 金枪鱼群优化&#xff08;Tuna Swarm Optimization,TSO&#xff09;的主要…

【Diffusion实战】训练一个类别引导diffusion模型(Pytorch代码详解)

又学习了一种方法&#xff0c;类别引导diffusion模型&#xff0c;使用mnist数据集&#xff0c;记录一下它的用法吧。 Diffusion实战篇&#xff1a;   【Diffusion实战】训练一个diffusion模型生成S曲线&#xff08;Pytorch代码详解&#xff09;   【Diffusion实战】训练一个…

store内路由跳转router.push

选择action还是mutation 选择action mutation 是用来改变state的&#xff0c;不应该包含路由相关操作mutation是同步执行的&#xff0c;不应该包含异步操作&#xff0c;而路由是异步操作 action中进行路由跳转 因为vuex中没有this&#xff0c;所以不能用this.$router&#…

Rust Course学习(编写测试)

如果友友你的计算机上没有安装Rust&#xff0c;可以直接安装&#xff1a;Rust 程序设计语言 (rust-lang.org)https://www.rust-lang.org/zh-CN/ Introduce 介绍 Testing in Rust involves writing code specifically designed to verify that other code works as expected. It…

2024.5.7

槽函数声明 private slots:void on_ed_textChanged();void on_pushButton_clicked(); }; 槽函数定义 void Widget::on_ed_textChanged()//文本框 {if(ui->ed1->text().length()>5&&ui->ed2->text().length()>5){ui->pushButton->setStyleSh…

Xinstall广告效果监测,助力广告主优化投放策略

在移动互联网时代&#xff0c;APP推广已成为企业营销的重要手段。然而&#xff0c;如何衡量推广效果&#xff0c;了解用户来源&#xff0c;优化投放策略&#xff0c;一直是广告主和开发者面临的难题。这时&#xff0c;Xinstall作为国内专业的App全渠道统计服务商&#xff0c;以…

实名认证的接口方式、PHP身份证实名认证接口集成

身份证实名认证接口用于验证用户提交身份信息的真实性和有效性&#xff0c;开发者可以下载开发者示例快速的将身份证实名认证接口功能集成到自己的应用中&#xff0c;以此来保障用户的身份信息不被泄露和滥用。 翔云身份证实名认证接口可以通过身份证号、姓名、证件人像、现场…

Docker 安装部署 postgres

Docker 安装部署 postgres 1、拉取 postgres 镜像文件 [rootiZbp19a67kznq0h0rgosuxZ ~]# docker pull postgres:latest latest: Pulling from library/postgres b0a0cf830b12: Pull complete dda3d8fbd5ed: Pull complete 283a477db7bb: Pull complete 91d2729fa4d5: Pul…

RT-DETR-20240507周更说明|更新Inner-IoU、Focal-IoU、Focaler-IoU等数十种IoU计算方式

RT-DETR改进专栏|包含主干、模块、注意力、损失函数等改进 专栏介绍 本专栏包含模块、卷积、检测头、损失等深度学习前沿改进,目前已有改进点70&#xff01;每周更新。 20240507更新说明&#xff1a; ⭐⭐ 更新CIoU、DIoU、MDPIoU、GIoU、EIoU、SIoU、ShapeIou、PowerfulIoU、…

数据结构-自定义栈、队列、二分查找树、双向链表

/*** 底层是数组*/ public class MyStack {private long [] arr; // 底层是数组private int top -1; // 核心【栈顶的索引&#xff08;指针&#xff09;】public MyStack() {super();arr new long[10];}public MyStack(int capacity) {super();arr new long[capacity]; // 自…

leetcode刷题:884、977

884.比较含退格的字符串 给定 s 和 t 两个字符串&#xff0c;当它们分别被输入到空白的文本编辑器后&#xff0c;如果两者相等&#xff0c;返回 true 。# 代表退格字符。 注意&#xff1a;如果对空文本输入退格字符&#xff0c;文本继续为空。 方法一、用栈 #include <i…

8.MyBatis 操作数据库(进阶)

文章目录 1.动态SQL插入1.1使用注解方式插入数据1.2使用xml方式插入数据1.3何时用注解何时用xml&#xff1f;1.4使用SQL查询中有多个and时&#xff0c;如何自动去除多余and1.4.1方法一&#xff1a;删除and之后的代码如图所示&#xff0c;再次运行1.4.2方法二&#xff1a;加上tr…

Linux服务器上网络端口测试

在使用telnet 111.22.345.66 80在Linux主机上尝试连接目标IP地址111.22.345.66的80端口时&#xff0c;会看到以下四行返回信息的含义解释&#xff1a; Trying 111.22.345.66...&#xff1a; 这一行指示telnet正在尝试与IP地址为111.22.345.66的主机建立连接。这表明telnet正尝…