1.小鸟默认向右向下飞,按空格或左键会使小鸟弹起向上
2.小鸟每通过一根柱子,分数加1
3.若小鸟碰到柱子或边框,游戏结束
4.添加图片+添加声音
【代码素材文件、工程文件】:https://ws28.cn/f/2auwqrnj5ig
或者:https://download.csdn.net/download/weixin_43503632/12331258
若链接失效,下方评论我会再发
#include
#include
#include
#include //需要提前下载(EasyX库函数)
#include
#pragma comment(lib,"Winmm.lib")//音乐
/*
《flappy bird》 by:你最珍贵
--------------------------------------
| 控制信号:| 向上 | 暂停 |
--------------------------------------
| 操作 :| 空格&鼠标左键 | Esc&右键 |
--------------------------------------
1.小鸟默认向右向下飞,按空格或左键会使小鸟弹起向上
2.小鸟每通过一根柱子,分数加1
3.若小鸟碰到柱子或边框,游戏结束
*/
/*
声音导入与使用
播放MP3,使用API函数mciSendString。
使用前,需要在函数外引用 Windows Multimedia API
#pragma comment(lib,"Winmm.lib")
下面这两条语句可以循环播放背景音乐
mciSendString("open E:\\background.mp3 alias bkmusic", NULL, 0,NULL);//背景音乐
mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循环播放
下面可以播放一次音效
mciSendString("open E:\\Jump.mp3 alias jpmusic", NULL, 0, NULL); //打开跳动音乐
mciSendString("play jpmusic", NULL, 0, NULL); // 仅播放一次
!!!如果文件名中有空格,需要用双引号引起来文件名(注意转义):
mciSendString("open \"D:\\My Music\\俞丽拿 梁祝 化蝶.mp3\" alias mymusic", NULL, 0, NULL);
*/
int bird_width;//小鸟宽
int bird_long;//小鸟长
int column_width;//柱子宽度
int column_long;//柱子长度
int interface_x;//图形窗口大小(宽*长)
int interface_y;
int IsEnd;//是否结束
int scores;//分数
int slow_v,slow_v_num;//移动变慢的值(越大速度越慢),移动变慢的变量
int slow_vbird,slow_vbird_num;//小鸟移动变慢的值(越大速度越慢),移动变慢的变量
int bird_x,bird_y;//小鸟位置
int bird_jump; //小鸟跳跃变量 =0时不跳 =3、2、1时跳跃
int column_x[2],column_y[2];//柱子位置
IMAGE img_bk,img_bk1,img_bked;//背景
IMAGE img_bd1, img_bd2;//bird(1为遮罩图,2为原图)
IMAGE img_clup1,img_clup2,img_cldown1,img_cldown2;//柱子上、柱子下
IMAGE gameover1,gameover2;//gameover图片
IMAGE score1[10],score2[10];//分数图片
void startup(){ //【数据初始化】
bird_width=34;
bird_long=24;
column_width=140;//柱子宽度
column_long=600;//柱子长度
interface_x=350;//图形窗口大小(宽*长)
interface_y=600;
IsEnd = 0;
scores=0;
slow_v=40;
slow_v_num=1;
bird_x=interface_x/4;//小鸟位置
bird_y=interface_y/2;
bird_jump=0;
slow_vbird=8;//小鸟的慢速变量
slow_vbird_num=1;
column_x[0]=interface_x;//柱子位置
column_y[0]=(-1)*column_long+(1.0/12)*interface_y+rand()%(interface_y*7/12);
column_x[1]=column_x[0]+interface_x;//第二根柱子默认在之后相差一个屏幕宽
column_y[1]=(-1)*column_long+(1.0/12)*interface_y+rand()%(interface_y*7/12);
//加载背景图、小鸟图、柱子上下gameover
loadimage(&img_bk,"素材库\\backgroundfd.jpg");//加载图片,()中 &后加图片变量、""中加图片地址(图片在工程中可以写相对地址,前面的不用写)(注意转义字符\\)
loadimage(&img_bk1,"素材库\\backgroundfd1.jpg");
loadimage(&img_bked,"素材库\\beforegame.jpg");
loadimage(&img_bd1,"素材库\\bird1-1.gif");//小鸟
loadimage(&img_bd2,"素材库\\bird1-2.gif");
loadimage(&img_clup1,"素材库\\stone_up2.gif");//柱子上
loadimage(&img_clup2,"素材库\\stone_up1.gif");
loadimage(&img_cldown1,"素材库\\stone_down2.gif");//柱子下
loadimage(&img_cldown2,"素材库\\stone_down1.gif");
loadimage(&gameover1, "素材库\\gameover1.gif");//GAMEOVER字样图片
loadimage(&gameover2, "素材库\\gameover2.gif");
//加载0 ~ 9数字
loadimage(&score1[0],"素材库\\0_1.jpg");
loadimage(&score2[0],"素材库\\0_2.jpg");
loadimage(&score1[1],"素材库\\1_1.jpg");
loadimage(&score2[1],"素材库\\1_2.jpg");
loadimage(&score1[2],"素材库\\2_1.jpg");
loadimage(&score2[2],"素材库\\2_2.jpg");
loadimage(&score1[3],"素材库\\3_1.jpg");
loadimage(&score2[3],"素材库\\3_2.jpg");
loadimage(&score1[4],"素材库\\4_1.jpg");
loadimage(&score2[4],"素材库\\4_2.jpg");
loadimage(&score1[5],"素材库\\5_1.jpg");
loadimage(&score2[5],"素材库\\5_2.jpg");
loadimage(&score1[6],"素材库\\6_1.jpg");
loadimage(&score2[6],"素材库\\6_2.jpg");
loadimage(&score1[7],"素材库\\7_1.jpg");
loadimage(&score2[7],"素材库\\7_2.jpg");
loadimage(&score1[8],"素材库\\8_1.jpg");
loadimage(&score2[8],"素材库\\8_2.jpg");
loadimage(&score1[9],"素材库\\9_1.jpg");
loadimage(&score2[9],"素材库\\9_2.jpg");
initgraph(interface_x,interface_y);//初始化图形窗口
BeginBatchDraw();//批量绘图开始_1
}
void show_begin(){//【初始页面展示】
static int i;
//输出背景、柱子、小鸟12、
putimage(0,0,&img_bked,NOTSRCERASE);//背景开始遮罩
putimage(0,0,&img_bk1,SRCINVERT);//背景
for(i=0;i<=1;i++){//柱子
//输出图片()中前两个,,表示图片左上角放置位置,第三个是&图片名称,第四个是输出格式(需要的加)(若是遮罩图+图片。输出一对,则遮罩图后是NOTSRCERASE、原图后是SRCINVERT)
putimage(column_x[i],column_y[i],&img_clup1,NOTSRCERASE); //上柱子遮罩图,遮罩图是为了把长方形图片中不想输出的部分减去不输出
putimage(column_x[i],column_y[i],&img_clup2,SRCINVERT);//上柱子
putimage(column_x[i],column_y[i]+750,&img_cldown1,NOTSRCERASE);//下柱子遮罩图
putimage(column_x[i],column_y[i]+750,&img_cldown2,SRCINVERT);//下柱子
}
putimage(bird_x,bird_y,&img_bd1,NOTSRCERASE);//小鸟遮罩图
putimage(bird_x,bird_y,&img_bd2,SRCINVERT); //小鸟原图
FlushBatchDraw();//前面都花完了再更新一次画面_2,解决画面闪的问题,需要配合BeginBatchDraw函数使用
cleardevice();//清除之前的画迹
//加载音乐 ("open 声音地址 alias 声音名称",NULL, 0,NULL)。
//若声音地址有空格需要在两端加\" \",即("open \"声音地址\" alias 声音新名称",NULL, 0,NULL)
mciSendString(" open \"素材库\\rdbkmusic.mp3\" alias rdbkmusic", NULL, 0,NULL);//准备背景音乐
//播放一次音乐("play 声音名称") !循环播放音乐("play 声音名称 repeat")
mciSendString("play rdbkmusic repeat", NULL, 0, NULL); //准备背景音乐循环播放
system("pause");//暂停
mciSendString(" open \"素材库\\happy bkmusic.mp3\" alias bkmusic", NULL, 0,NULL);//背景音乐
mciSendString("play bkmusic repeat", NULL, 0, NULL); // 循环播放背景音乐
mciSendString("stop rdbkmusic", NULL, 0, NULL); //准备背景音乐停止
mciSendString("close rdbkmusic", NULL, 0, NULL); //准备背景音乐关闭
}
void scoreprint()//显示分数页面
{
int he,weishu=1,sdsf=scores;//从低位起依次取分数每位的数值、分数的位数、分数代替值(之后要做运算用)
if(sdsf==0)//分数为0时
{
putimage(310,45,&score1[0],NOTSRCERASE);//分数0
putimage(310,45,&score2[0],SRCINVERT);
}
while(sdsf>0)//分数不为0时
{
he=sdsf%10; //取最低位置
putimage(340-30*weishu,45,&score1[he],NOTSRCERASE);//输出数字图片(遮罩图+原图)
putimage(340-30*weishu,45,&score2[he],SRCINVERT);
sdsf/=10;//每输出一位,去掉最后一位
weishu++;//下一位输出的是分数的第几位(从右边数)
}
}
void show(){ //【显示画面】
static int i;
//输出背景、柱子、小鸟12、
putimage(0,0,&img_bk);//背景
for(i=0;i<=1;i++){//柱子
putimage(column_x[i],column_y[i],&img_clup1,NOTSRCERASE);
putimage(column_x[i],column_y[i],&img_clup2,SRCINVERT);
putimage(column_x[i],column_y[i]+750,&img_cldown1,NOTSRCERASE);
putimage(column_x[i],column_y[i]+750,&img_cldown2,SRCINVERT);
}
putimage(bird_x,bird_y,&img_bd1,NOTSRCERASE);//小鸟
putimage(bird_x,bird_y,&img_bd2,SRCINVERT);
scoreprint();//显示分数
FlushBatchDraw();//更新一次画面_2,解决画面闪的问题,需要配合BeginBatchDraw函数使用
cleardevice();//清除之前的画迹
}
void update_outinput(){ //【与输入无关的更新】
static int i;
if(bird_y<=0 || bird_y+bird_long>=interface_y){//小鸟是否碰到边界
IsEnd=1;
}
for(i=0;i<=1;i++){//小鸟是否碰到柱子,是否通过柱子
if(bird_x>=column_x[i] && bird_x<column_x[i]+column_width||column_x[i]-bird_x>=0 && column_x[i]-bird_x<bird_long){
if(bird_y+bird_long>column_y[i]+4+750 || bird_y<column_y[i]-4+600){
IsEnd=1;
break;
}
}
if(slow_v_num==slow_v&&bird_x>=column_x[i]+column_width+1&&bird_x<=column_x[i]+column_width+4){//小鸟通过柱子
scores++;
mciSendString("close scoremusic", NULL, 0, NULL); // 关闭加分音乐(若是多次播放,每次播放前需要close该音乐)
mciSendString(" open \"素材库\\score music.mp3\" alias scoremusic", NULL, 0,NULL);//加分音乐
mciSendString("play scoremusic", NULL, 0, NULL); // 播放加分音乐
}
}
slow_v_num=(slow_v_num==slow_v)? 1:slow_v_num+1;//柱子
if(slow_v_num==slow_v){//每隔slow_v次运行一次
for(i=0;i<=1;i++){
if(column_x[i] <= (-1)*column_width){//如果柱子到最左,重置位置
column_x[i] = 2*interface_x;
column_y[i]=(-1)*column_long+(1.0/12)*interface_y+rand()%(interface_y*7/12);
}else{
column_x[i] -= 4;//柱子每次左移4单位
}
}
}
slow_vbird_num=(slow_vbird_num==slow_vbird)? 1:slow_vbird_num+1;//小鸟
if(slow_vbird_num==slow_vbird){//每隔slow_vbird次运行一次
bird_y +=1;//小鸟默认下降1
if(bird_jump>0){//如果按下空格,循环bird_jum次
bird_y -= 6;//每次上升6和上下降的1,总共上升5
bird_jump--;
}
}
}
void update_input(){//【与输入有关的更新】
char input;
MOUSEMSG m;//鼠标信息类型
if(kbhit()){
input = getch();
if(input==' '){
mciSendString("close doin", NULL, 0, NULL); // 关闭按键音乐
mciSendString(" open \"素材库\\doin.mp3\" alias doin", NULL, 0,NULL);//加分音乐
mciSendString("play doin", NULL, 0, NULL); // 播放按键音乐
if(bird_jump>0) bird_y=bird_y-5;//如果按下空格前也检测到有空格,则位置额外-5
bird_jump=12;//之后要上升的次数
}else if(input==0x1b){//按下esc暂停;input==0x1b代表按下ESC键
system("pause");
}
}else if(MouseHit()){//如果有鼠标信息
m = GetMouseMsg();//鼠标信息赋值给m
if(m.uMsg == WM_LBUTTONDOWN){//如果m=左键按下
mciSendString("close doin", NULL, 0, NULL); // 关闭按键音乐
mciSendString(" open \"素材库\\doin.mp3\" alias doin", NULL, 0,NULL);//加分音乐
mciSendString("play doin", NULL, 0, NULL); // 播放按键音乐
if(bird_jump>0) bird_y=bird_y-5;//如果按下空格前也检测到有空格,则位置额外-5
bird_jump=12;//之后要上升的次数
}else if(m.uMsg == WM_RBUTTONDOWN){//右键按下暂停
system("pause");
}
}
}
void show_end(){//【显示失败界面】
mciSendString("stop bkmusic", NULL, 0, NULL); // 暂停背景音乐
mciSendString(" open \"素材库\\deing.mp3\" alias downmusic", NULL, 0,NULL);//背景音乐
mciSendString("play downmusic", NULL, 0, NULL); // 播放下落音乐
mciSendString(" open \"素材库\\gameover.mp3\" alias gameover", NULL, 0,NULL);//背景音乐
mciSendString("play gameover", NULL, 0, NULL); // 播放gameover音乐
mciSendString("close bkmusic", NULL, 0, NULL); // 关闭背景音乐
static int i;
//输出背景、柱子、小鸟12、
putimage(0,0,&img_bk);//背景
for(i=0;i<=1;i++){//柱子
putimage(column_x[i],column_y[i],&img_clup1,NOTSRCERASE);
putimage(column_x[i],column_y[i],&img_clup2,SRCINVERT);
putimage(column_x[i],column_y[i]+750,&img_cldown1,NOTSRCERASE);
putimage(column_x[i],column_y[i]+750,&img_cldown2,SRCINVERT);
}
putimage(bird_x,bird_y,&img_bd1,NOTSRCERASE);//小鸟
putimage(bird_x,bird_y,&img_bd2,SRCINVERT);
scoreprint();//显示分数
putimage(80, 200, &gameover1,NOTSRCERASE);//gamoover图片
putimage(80, 200, &gameover2,SRCINVERT);
FlushBatchDraw();//更新一次画面_2,解决画面闪的问题,需要配合BeginBatchDraw函数使用
cleardevice();//清除之前的画迹
system("pause");//暂停
}
int main(){
startup(); //数据初始化
show_begin();//初始页面
while(!IsEnd){ //游戏循环执行
if(!IsEnd) show(); // 显示画面
if(!IsEnd) update_outinput(); //与输入无关的更新
if(!IsEnd) update_input(); //与输入有关的更新
}
show_end(); //显示失败界面
EndBatchDraw();//结束批量绘制
closegraph();//关闭窗口
return 0;
}