C语言小游戏(flappy bird),附带源码及素材

前言

这是我写的第一个程序,写一篇文章纪念一下,同时也给后续刚刚开始学习计算机的同学们一个参考。

注意:完成该程序需要用到easy-x库下<graphics.h>数据,建议用vc6或vs2013版本以上等支持安装easy-x库的软件
easy-x库安装挺简单的,见
Easy-X安装
https://blog.csdn.net/qq_43605229/article/details/97611837

一、系统简介及最终效果

在这里插入图片描述
该游戏名为FLIP 滑稽,改自flappy bird。游戏实现了按空格键跳跃,越过障碍无得分,触碰障碍物边界或游戏窗口上下边界游戏结束的功能。其中图片、音效、文件写入/读取、键盘输入、鼠标输入的交互让游戏的体验更加良好。游戏主菜单下有多个模块供选择,可以开始/继续/退出游戏及获取有关帮助和游戏相关信息。游戏过程中可以随时暂停返回主菜单或选择继续游戏。游戏结束后也可选择返回主菜单或是重新开始或是退出游戏。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、函数模块图及所需的一些材料素材下载

函数模块图
下图为我编程时所用到的图片和音频文件(积分下载材料点这里),百度云盘下载点这里,提取码2333 (可以的话积分下载支持一下呀)大家不一定要用我的材料,可以用自己喜欢的图片与音频文件,建议将这些材料放在一个文件夹里方便后面的引用。
在这里插入图片描述

三、具体代码(在代码中有具体的解释)

我是在安装了easy-x库的VC6.0下运行的

1、头文件

// #include<bits/stdc++.h>
#include<stdio.h>
#include <conio.h>
#include <time.h>
#include <graphics.h>
#pragma comment(lib,"Winmm.lib")//导入音乐等多媒体

void main();//主函数
void startup();//初始化
void show();//画面显示
void updateWithInput();//与玩家输入有关的画面数据更新
void updateWithoutInput();//与玩家输入无关的画面数据更新
void gameOver();//结束处理

void startMenu();//开始菜单
oid pauseMenu();//暂停菜单
void overMenu();//结束菜单
void readHelpFile();//打开帮助页面
void readAboutFile();//打开关于页面
void readRecordFile();//读档
void writeRecordFile();//存档

#define High 600    //定义游戏界面的高度
#define Width 600   //定义游戏界面的宽度
#define Difficulty 10 //定义游戏难度(用Sleep函数控制快慢)

2、全局变量定义

//定义全局变量
IMAGE
huaji1,huaji2,img_bk,tiao1,tiao2,pause,help,about,shang1,shang2,xia1,xia2,over1,over2,over3,over4;//各种图片
int huaji_x,huaji_y;//滑稽的坐标
int bar_x,shang_y,xia_y;//障碍的坐标
int score;//得分

//定义游戏状态:若为0初始化后显示主菜单,若为1直接进入游戏
int gameStatus=0;

3、存读档函数

//读取游戏存档,实现“继续游戏”
void readRecordFile()
{
    FILE *fp;
    fp=fopen("F:\\游戏记录.txt","r");
    fscanf(fp,"%d %d %d %d %d %d",&huaji_x,&huaji_y,&bar_x,&shang_y,&xia_y,&score);//游戏核心数据读出
    fclose(fp);
}
//游戏数据写入存档,保存游戏记录
void writeRecordFile()
{
    FILE *fp;
    fp=fopen("F:\\游戏记录.txt","w+");
    fprintf(fp,"%d %d %d %d %d %d",huaji_x,huaji_y,bar_x,shang_y,xia_y,score);//游戏核心数据写入
    fclose(fp);
}

4、关于/帮助菜单函数

//主菜单里的“帮助”界面
void readHelpFile()
{ 
    loadimage(&help,"F:\\帮助.jpg");//打开帮助界面背景图片
    putimage(0,0,&help);
    FlushBatchDraw();
    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\帮助.mp3 alias help",NULL,0,NULL);//打开帮助界面背景音乐
    mciSendString("play help repeat",NULL,0,NULL);//播放

    FILE *fp;
    char s[32];
    fp=fopen("F:\\帮助.txt","r");//读取“帮助”文档
    int length=25;   //定义行间距
    while(!feof(fp)) // 经过试验发现每行32个字符很适合
    {

      fgets(s,32,fp);
 
      setbkmode(TRANSPARENT);//透明化文字背景
      settextcolor(WHITE);
      settextstyle(20,0,_T("楷体"));
      outtextxy(25,length, s);//将字符串输出到界面对应坐标位置上
      length+=25;
    }
     settextcolor(YELLOW);
     settextstyle(35,0,_T("华文新魏"));
     outtextxy(0,555,"温馨提示:点击屏幕任意位置回主菜单");//在底端输出温馨提示
     Sleep(1000);
     FlushBatchDraw();

     fclose(fp);
     MOUSEMSG m;//用鼠标控制退出帮助界面回到主菜单
     while(1)
     { 
          m=GetMouseMsg();
          if(m.uMsg==WM_LBUTTONDOWN)
         {
          mciSendString("close help",NULL,0,NULL);//左击任意位置回主菜单
          gameStatus=0;
          main();
         }
     }
}

//主菜单里的“关于”界面
void readAboutFile()
{
    loadimage(&about,"F:\\关于.jpg");//打开关于界面背景图片
    putimage(0,0,&about);
    FlushBatchDraw();

    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\关于.mp3 alias about",NULL,0,NULL);//打开帮助界面背景音乐
    mciSendString("play about repeat",NULL,0,NULL);//播放

    FILE *fp;
    char s[80];
    fp=fopen("F:\\关于.txt","r");
    fgets(s,80,fp);

    setbkmode(TRANSPARENT);//背景透明
    settextcolor(BLACK);
    settextstyle(50,0,_T("华文彩云"));
    outtextxy(250,0,"关于");

    settextstyle(30,0,_T("华文行楷"));//输出关于界面的相关内容(内容较少就不用文本了直接写入)
    outtextxy(240,60,"关于的话");
    outtextxy(250,95,"emmmmmm");
    outtextxy(150,130,"这是个非常好玩的游戏");
    outtextxy(250,165,"嗯 没错");
    outtextxy(240,195,"就是这样");

    settextcolor(RED);
    settextstyle(35,0,_T("华文新魏"));
    outtextxy(0,555,"温馨提示:点击屏幕任意位置回主菜单");
    Sleep(1000);
    FlushBatchDraw();

    fclose(fp);
    MOUSEMSG m;//用鼠标控制退出帮助界面回到主菜单
    while(1)
    {
        m=GetMouseMsg();
        if(m.uMsg==WM_LBUTTONDOWN)
        { 
          mciSendString("close about",NULL,0,NULL);//左击任意位置回主菜单
          gameStatus=0;
          main();
        }
    }
}

5、主菜单/暂停菜单/结束菜单函数

//主菜单界面
void startMenu()
{
    mciSendString("close bkmusic_2",NULL,0,NULL);//关闭背景音乐
    loadimage(&pause,"F:\\初始化界面.jpg");//打开初始化界面背景图片
    putimage(0,0,&pause);
    FlushBatchDraw();
    
    setbkmode(TRANSPARENT);//背景透明
    settextcolor(YELLOW);
    settextstyle(50,0,_T("华文行楷"));//在对应位置输出菜单选项内容
    outtextxy(175,150,"1 开始游戏");
    outtextxy(175,250,"2 继续游戏");   
    outtextxy(50,350,"3 什么游戏,我要学习!");
    
   settextcolor(WHITE);//这两个内容用不同字体
    settextstyle(40,0,_T("华文彩云"));
    outtextxy(50,500,"4 帮助");
    outtextxy(425,500,"5 关于");   

    char input;//判断是否有键盘输入
    if(kbhit())
    {
        input=getch();
        if(input=='1')
        gameStatus=1;//进入新游戏
        else if(input=='2')
        {
          readRecordFile();//读取存档,继续游戏
          gameStatus=1;
        }
        else if(input=='3')
        {
            gameStatus=1;//去学习,退出游戏
            exit(0);
        }
        else if(input=='4')
        {
            while(1)//让内容长久显示
            readHelpFile();//读取帮助界面内容
        }
        else if(input=='5')
        {
            while(1)//让内容长久显示
            readAboutFile();//读取关于界面内容
        }
    }
}
//暂停菜单界面
void pauseMenu()
{
   while(1)//让内容长久显示
   {
    loadimage(&pause,"F:\\暂停时的图片.jpg");//打开暂停菜单的背景图片
    putimage(0,0,&pause);
    FlushBatchDraw();

    char input;
    if(kbhit())//判断是否有鼠标输入
    {
        input=getch();
        if(input=='1')//开始新游戏
        {
            gameStatus=1;//不进入主菜单,直接开始新游戏
            main();
        }
        else if(input=='2')//继续游戏
        {  
            startup();//从头开始初始化后读取存档,继续游戏
            readRecordFile();//读取存档
            show();
            Sleep(1400);//预备开始阶段延时
            while(1)//游戏循环执行
          {
            show();//显示画面
            updateWithoutInput();//与玩家输入无关的游戏界面更新
            updateWithInput();//与玩家输入有光的游戏界面更新
          }
        }
        else if(input=='3')//回主菜单
        {
            gameStatus=0;
            startup();
            putimage(0,0,&img_bk);  //打开预备开始阶段背景画面
            FlushBatchDraw();
            show();
            Sleep(1400);//预备开始阶段延时
            break;
        }
        else if(input=='4')//退出游戏
        {
            gameStatus=1;
            exit(0);
        }
    }
   }
}

void overMenu()
{
    while(1) //让结束菜单长久显示
    {
        loadimage(&over4,"F:\\结束时的背景图片.jpg");
        putimage(0,0,&over4);
        setbkmode(TRANSPARENT);//透明化文字背景
        settextcolor(WHITE);
        settextstyle(50,0,_T("华文行楷"));
        outtextxy(Width-500,High-500,"1 不够爽!再来一局!");//输出菜单内容
        outtextxy(Width-500,High-400,"2 我想回主菜单了");   
        outtextxy(Width-500,High-300,"3 我要去学习了!!!"); 

        settextcolor(YELLOW);          
        settextstyle(50,0,_T("华文彩云"));
        outtextxy(Width-425,High-200,"得分: ");    //显示得分
        char s[10];
        sprintf(s,"%d",score);
        outtextxy(Width-275,High-200,s);   
        FlushBatchDraw();

        char input;  //判断是否有键盘输入
        if(kbhit())
        {
           input=getch();
           if(input=='1')//开始新游戏
          {
            gameStatus=1;
            main();
          }
          else if(input=='2')//回主菜单
          {
            gameStatus=0;//状态值为零,初始化后显示主菜单
            startup();

            putimage(0,0,&img_bk);  //打开背景画面
            FlushBatchDraw();
            show();
            Sleep(1400);
            break;
          }
           else if(input=='3')//去学习,退出游戏
           exit(0);
        }
      }
}

6、初始化函数

//初始化
void startup()  
{
   score=0;   //初始化分数为0
   initgraph(Width,High); //定义游戏界面大小

   loadimage(&img_bk,"F:\\背景图片.jpg");//打开一系列游戏界面的图片
    loadimage(&huaji1,"F:\\滑稽1.jpg");
    loadimage(&huaji2,"F:\\滑稽2.jpg");
    loadimage(&shang1,"F:\\上障碍1.jpg");
    loadimage(&shang2,"F:\\上障碍2.jpg");
    loadimage(&xia1,"F:\\下障碍1.jpg");
    loadimage(&xia2,"F:\\下障碍2.jpg");

    mciSendString("open F:\\背景音乐1.mp3 alias bkmusic_1",NULL,0,NULL);//打开背景音乐
    mciSendString("play bkmusic_1 repeat",NULL,0,NULL);//播放
    
    srand(time(NULL));  //利用系统时间产生伪随机种子,以为了得到随机位置的障碍

    huaji_x = 24;       //初始化滑稽坐标
    huaji_y = rand() % 150 + 250;
    bar_x = 450;        //初始化障碍的坐标
    shang_y = rand() % 400 - 550;
    while(xia_y - shang_y>730 || xia_y - shang_y<670) //上下障碍随机出现的坐标范围
    {
        shang_y = rand()%400 - 550;
        xia_y = rand()%300 + 150 ;
    }
    while(gameStatus==0)      //状态为0则进入主菜单
    {
        Sleep(200);
        startMenu();//主菜单界面
        FlushBatchDraw();
    }
    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\背景音乐2.mp3 alias bkmusic_2",NULL,0,NULL);//打开游戏背景音乐
    mciSendString("play bkmusic_2 repeat",NULL,0,NULL);//播放
    mciSendString("close beginmusic",NULL,0,NULL);
    mciSendString("open F:\\开始.mp3 alias beginmusic ",NULL,0,NULL);//播放一次开始时的预备音效
    mciSendString("play beginmusic",NULL,0,NULL);
}


7、其他辅助函数

//显示画面 
void show()
{
    Sleep(Difficulty);  //整体速度控制即难度
    putimage(0,0,&img_bk);  //打开背景画面
    //采用精灵图与掩码图叠加偶读方法实现抠图,让部分区域透明
    putimage(huaji_x,huaji_y,&huaji1,NOTSRCERASE);  //透明化边界外的图片
    putimage(huaji_x,huaji_y,&huaji2,SRCINVERT);    
    putimage(bar_x,shang_y,&shang1,NOTSRCERASE);//上障碍
    putimage(bar_x,shang_y,&shang2,SRCINVERT);
    putimage(bar_x,xia_y,&xia1,NOTSRCERASE);//下障碍
    putimage(bar_x,xia_y,&xia2,SRCINVERT);
    
    setbkmode(TRANSPARENT);//文字背景透明

    settextcolor(RED);
    settextstyle(50,0,_T("华文行楷"));
    outtextxy(0,0,"得分:");
    settextcolor(RED);  
    settextstyle(50,0,_T("Algerain"));//显示分数
    char s[10];
    sprintf(s,"%d",score);
    outtextxy(125,0,s);
    FlushBatchDraw();
}

//与输入有关的更新
void updateWithInput()  
{
    char input;
    if (kbhit())//判断是否有键盘输入
    {
        input = getch();
        if (input==' ')
        {   
        loadimage(&tiao1,"F:\\我跳1.jpg");
        loadimage(&tiao2,"F:\\我跳2.jpg");
        putimage(huaji_x,huaji_y,&tiao1,NOTSRCERASE);//每跳一下滑稽的表情就变一次
        putimage(huaji_x,huaji_y,&tiao2,SRCINVERT); 
        huaji_y-=30;//点一下空格滑稽就会上跳的高度

        mciSendString("close jpmusic",NULL,0,NULL);
        mciSendString("open F:\\跳.mp3 alias jpmusic ",NULL,0,NULL);//按一下空格播放一次音效
        mciSendString("play jpmusic",NULL,0,NULL);
        }
        else if(input==27)//27为esc 键的ascll码
        {
        writeRecordFile();//存档
        mciSendString("close bkmusic_2",NULL,0,NULL);//关闭游戏时的背景音乐
        pauseMenu();//打开暂停界面
        }
    }
}

//与玩家输入无关的游戏界面更新
void updateWithoutInput()
{
    if (huaji_y<High)   //自动下落
        huaji_y++;
    if (bar_x>-140)        //障碍左移,140为整个障碍的宽度
        bar_x--;
    else                   //障碍重新从右边出现
    {
        bar_x = Width;
        shang_y = rand()%300 - 450;
        while(xia_y - shang_y>730 || xia_y - shang_y<670)
        {
            shang_y =rand()%300 - 450;
            xia_y = rand()%300 + 150 ;
        }
    }
    
    if (((bar_x<50 && bar_x>-100) && (huaji_y+40>xia_y || huaji_y<shang_y+585)) || (huaji_y>550 || huaji_y<0 ))//判断失败
    {
        mciSendString("close bkmusic_2",NULL,0,NULL);//关闭背景音乐
        mciSendString("close overmusic_1",NULL,0,NULL);
        mciSendString("open F:\\尖叫.mp3 alias overmusic_1 ",NULL,0,NULL);//播放触碰危险边缘的尖叫音效
        mciSendString("play overmusic_1",NULL,0,NULL);

      loadimage(&over1,"F:\\我输了1.jpg");//还是用两图叠加的方法实现 失败时表情边缘的透明
        loadimage(&over2,"F:\\我输了2.jpg");
        putimage(huaji_x,huaji_y,&over1,NOTSRCERASE);//输了后滑稽变为 失败时 的表情
        putimage(huaji_x,huaji_y,&over2,SRCINVERT);
        FlushBatchDraw();
        Sleep(2000);//表情出现后停留一段时间

        mciSendString("close overmusic_2",NULL,0,NULL);
        mciSendString("open F:\\失败.mp3 alias overmusic_2 ",NULL,0,NULL);//播放 失败后 的背景音乐
        mciSendString("play overmusic_2",NULL,0,NULL);
        loadimage(&over3,"F:\\不要打扰我学习.jpg");//打开 失败后 的背景图片
        putimage(0,0,&over3);
        FlushBatchDraw();
        Sleep(5000);//图片出现后停留一段时间
         overMenu();
    }
         if
(bar_x==-90) //跳过障碍后加一分
         {
           score++;
           mciSendString("close score",NULL,0,NULL);
           
           mciSendString("open F:\\加一.mp3 alias score",NULL,0,NULL);//打开加分时的音效
           mciSendString("play score",NULL,0,NULL);
        }
}
//游戏结束处理
void gameOver()
{
    EndBatchDraw();//结束绘图
    closegraph();//关闭图片
}

8、主函数

void main()
{
    startup();              //数据初始化
    show();                 //显示画面(这一画面为准备阶段的画面)
    Sleep(1400);            //游戏准备阶段的延时
    while(1)//游戏循环执行
    {
        show();                           //再次显示画面(游戏开始玩时的界面)
        updateWithoutInput();//与玩家输入无关的游戏界面更新
        updateWithInput();//与玩家输入有光的游戏界面更新
    }
   gameOver();//游戏结束处理
}

四、一些图片处理原理

图片处理主要就是抠图,把想要的步伐取出来,emmmm,那就以下面这个东西为例子吧。
我们先找到自己所需要的图,就像下面这个,我想让这个图片在程序运行的时候没有外面的那一圈白边,也就是把中间那个表情抠出来。
那我们就需要用到修图软件做出左边这张图(我是用PS做的)
来个PS教程:打开photoshop,打开上面菜单栏中【图像】→【调整】→【阈值】,然后调整阈值得到想要的黑白图片,就像下面左边这张图一样(我们要抠的部分是白色,不要的部分是黑色)
在这里插入图片描述

loadimage(&tiao1,"F:\\我跳1.jpg"); //导入图片
loadimage(&tiao2,"F:\\我跳2.jpg");
putimage(huaji_x,huaji_y,&tiao1,NOTSRCERASE);  //这里输入一张黑白图
putimage(huaji_x,huaji_y,&tiao2,SRCINVERT);        // 这里输入原图

经过这几行代码的处理,在程序中就会把我们所需要的表情扣出来,不会有边缘的白边

五、完整源代码

#include<stdio.h>
#include <conio.h>
#include <time.h>
#include <graphics.h>
#pragma comment(lib,"Winmm.lib")//导入音乐等多媒体

void main();//主函数
void startup();//初始化
void show();//画面显示
void updateWithInput();//与玩家输入有关的画面数据更新
void updateWithoutInput();//与玩家输入无关的画面数据更新
void gameOver();//结束处理

void startMenu();//开始菜单
void pauseMenu();//暂停菜单
void overMenu();//结束菜单
void readHelpFile();//打开帮助页面
void readAboutFile();//打开关于页面
void readRecordFile();//读档
void writeRecordFile();//存档

#define High 600    //定义游戏界面的高度
#define Width 600   //定义游戏界面的宽度
#define Difficulty 10 //定义游戏难度(用Sleep函数控制快慢)

//定义全局变量
IMAGE
huaji1,huaji2,img_bk,tiao1,tiao2,pause,help,about,shang1,shang2,xia1,xia2,over1,over2,over3,over4;//各种图片
int huaji_x,huaji_y;//滑稽的坐标
int bar_x,shang_y,xia_y;//障碍的坐标
int score;//得分

//定义游戏状态:若为0初始化后显示主菜单,若为1直接进入游戏
int gameStatus=0;

//读取游戏存档,实现“继续游戏”
void readRecordFile()
{
    FILE *fp;
    fp=fopen("F:\\游戏记录.txt","r");
    fscanf(fp,"%d %d %d %d %d %d",&huaji_x,&huaji_y,&bar_x,&shang_y,&xia_y,&score);//游戏核心数据读出
    fclose(fp);
}
//游戏数据写入存档,保存游戏记录
void writeRecordFile()
{
    FILE *fp;
    fp=fopen("F:\\游戏记录.txt","w+");
    fprintf(fp,"%d %d %d %d %d %d",huaji_x,huaji_y,bar_x,shang_y,xia_y,score);//游戏核心数据写入
    fclose(fp);
}


//主菜单里的“帮助”界面
void readHelpFile()
{ 
    loadimage(&help,"F:\\帮助.jpg");//打开帮助界面背景图片
    putimage(0,0,&help);
    FlushBatchDraw();
    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\帮助.mp3 alias help",NULL,0,NULL);//打开帮助界面背景音乐
    mciSendString("play help repeat",NULL,0,NULL);//播放

    FILE *fp;
    char s[32];
    fp=fopen("F:\\帮助.txt","r");//读取“帮助”文档
    int length=25;   //定义行间距
    while(!feof(fp)) // 经过试验发现每行32个字符很适合
    {

      fgets(s,32,fp);
 
      setbkmode(TRANSPARENT);//透明化文字背景
      settextcolor(WHITE);
      settextstyle(20,0,_T("楷体"));
      outtextxy(25,length, s);//将字符串输出到界面对应坐标位置上
      length+=25;
    }
     settextcolor(YELLOW);
     settextstyle(35,0,_T("华文新魏"));
     outtextxy(0,555,"温馨提示:点击屏幕任意位置回主菜单");//在底端输出温馨提示
     Sleep(1000);
     FlushBatchDraw();

     fclose(fp);
     MOUSEMSG m;//用鼠标控制退出帮助界面回到主菜单
     while(1)
     { 
          m=GetMouseMsg();
          if(m.uMsg==WM_LBUTTONDOWN)
         {
          mciSendString("close help",NULL,0,NULL);//左击任意位置回主菜单
          gameStatus=0;
          main();
         }
     }
}

//主菜单里的“关于”界面
void readAboutFile()
{
    loadimage(&about,"F:\\关于.jpg");//打开关于界面背景图片
    putimage(0,0,&about);
    FlushBatchDraw();

    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\关于.mp3 alias about",NULL,0,NULL);//打开帮助界面背景音乐
    mciSendString("play about repeat",NULL,0,NULL);//播放

    FILE *fp;
    char s[80];
    fp=fopen("F:\\关于.txt","r");
    fgets(s,80,fp);

    setbkmode(TRANSPARENT);//背景透明
    settextcolor(BLACK);
    settextstyle(50,0,_T("华文彩云"));
    outtextxy(250,0,"关于");

    settextstyle(30,0,_T("华文行楷"));//输出关于界面的相关内容(内容较少就不用文本了直接写入)
    outtextxy(240,60,"关于的话");
    outtextxy(250,95,"emmmmmm");
    outtextxy(150,130,"这是个非常好玩的游戏");
    outtextxy(250,165,"嗯 没错");
    outtextxy(240,195,"就是这样");

    settextcolor(RED);
    settextstyle(35,0,_T("华文新魏"));
    outtextxy(0,555,"温馨提示:点击屏幕任意位置回主菜单");
    Sleep(1000);
    FlushBatchDraw();

    fclose(fp);
    MOUSEMSG m;//用鼠标控制退出帮助界面回到主菜单
    while(1)
    {
        m=GetMouseMsg();
        if(m.uMsg==WM_LBUTTONDOWN)
        { 
          mciSendString("close about",NULL,0,NULL);//左击任意位置回主菜单
          gameStatus=0;
          main();
        }
    }
}

//主菜单界面
void startMenu()
{
    mciSendString("close bkmusic_2",NULL,0,NULL);//关闭背景音乐
    loadimage(&pause,"F:\\初始化界面.jpg");//打开初始化界面背景图片
    putimage(0,0,&pause);
    FlushBatchDraw();
    
    setbkmode(TRANSPARENT);//背景透明
    settextcolor(YELLOW);
    settextstyle(50,0,_T("华文行楷"));//在对应位置输出菜单选项内容
    outtextxy(175,150,"1 开始游戏");
    outtextxy(175,250,"2 继续游戏");   
    outtextxy(50,350,"3 什么游戏,我要学习!");
    
   settextcolor(WHITE);//这两个内容用不同字体
    settextstyle(40,0,_T("华文彩云"));
    outtextxy(50,500,"4 帮助");
    outtextxy(425,500,"5 关于");   

    char input;//判断是否有键盘输入
    if(kbhit())
    {
        input=getch();
        if(input=='1')
        gameStatus=1;//进入新游戏
        else if(input=='2')
        {
          readRecordFile();//读取存档,继续游戏
          gameStatus=1;
        }
        else if(input=='3')
        {
            gameStatus=1;//去学习,退出游戏
            exit(0);
        }
        else if(input=='4')
        {
            while(1)//让内容长久显示
            readHelpFile();//读取帮助界面内容
        }
        else if(input=='5')
        {
            while(1)//让内容长久显示
            readAboutFile();//读取关于界面内容
        }
    }
}

//暂停菜单界面
void pauseMenu()
{
   while(1)//让内容长久显示
   {
    loadimage(&pause,"F:\\暂停时的图片.jpg");//打开暂停菜单的背景图片
    putimage(0,0,&pause);
    FlushBatchDraw();

    char input;
    if(kbhit())//判断是否有鼠标输入
    {
        input=getch();
        if(input=='1')//开始新游戏
        {
            gameStatus=1;//不进入主菜单,直接开始新游戏
            main();
        }
        else if(input=='2')//继续游戏
        {  
            startup();//从头开始初始化后读取存档,继续游戏
            readRecordFile();//读取存档
            show();
            Sleep(1400);//预备开始阶段延时
            while(1)//游戏循环执行
          {
            show();//显示画面
            updateWithoutInput();//与玩家输入无关的游戏界面更新
            updateWithInput();//与玩家输入有光的游戏界面更新
          }
        }
        else if(input=='3')//回主菜单
        {
            gameStatus=0;
            startup();
            putimage(0,0,&img_bk);  //打开预备开始阶段背景画面
            FlushBatchDraw();
            show();
            Sleep(1400);//预备开始阶段延时
            break;
        }
        else if(input=='4')//退出游戏
        {
            gameStatus=1;
            exit(0);
        }
    }
   }
}

 

void overMenu()
{
    while(1) //让结束菜单长久显示
    {
        loadimage(&over4,"F:\\结束时的背景图片.jpg");
        putimage(0,0,&over4);
        setbkmode(TRANSPARENT);//透明化文字背景
        settextcolor(WHITE);
        settextstyle(50,0,_T("华文行楷"));
        outtextxy(Width-500,High-500,"1 不够爽!再来一局!");//输出菜单内容
        outtextxy(Width-500,High-400,"2 我想回主菜单了");   
        outtextxy(Width-500,High-300,"3 我要去学习了!!!"); 

        settextcolor(YELLOW);          
        settextstyle(50,0,_T("华文彩云"));
        outtextxy(Width-425,High-200,"得分: ");    //显示得分
        char s[10];
        sprintf(s,"%d",score);
        outtextxy(Width-275,High-200,s);   
        FlushBatchDraw();

        char input;  //判断是否有键盘输入
        if(kbhit())
        {
           input=getch();
           if(input=='1')//开始新游戏
          {
            gameStatus=1;
            main();
          }
          else if(input=='2')//回主菜单
          {
            gameStatus=0;//状态值为零,初始化后显示主菜单
            startup();

            putimage(0,0,&img_bk);  //打开背景画面
            FlushBatchDraw();
            show();
            Sleep(1400);
            break;
          }
           else if(input=='3')//去学习,退出游戏
           exit(0);
        }
      }
}

//初始化
void startup()  
{
   score=0;   //初始化分数为0
   initgraph(Width,High); //定义游戏界面大小

   loadimage(&img_bk,"F:\\背景图片.jpg");//打开一系列游戏界面的图片
    loadimage(&huaji1,"F:\\滑稽1.jpg");
    loadimage(&huaji2,"F:\\滑稽2.jpg");
    loadimage(&shang1,"F:\\上障碍1.jpg");
    loadimage(&shang2,"F:\\上障碍2.jpg");
    loadimage(&xia1,"F:\\下障碍1.jpg");
    loadimage(&xia2,"F:\\下障碍2.jpg");

    mciSendString("open F:\\背景音乐1.mp3 alias bkmusic_1",NULL,0,NULL);//打开背景音乐
    mciSendString("play bkmusic_1 repeat",NULL,0,NULL);//播放
    
    srand(time(NULL));  //利用系统时间产生伪随机种子,以为了得到随机位置的障碍

    huaji_x = 24;       //初始化滑稽坐标
    huaji_y = rand() % 150 + 250;
    bar_x = 450;        //初始化障碍的坐标
    shang_y = rand() % 400 - 550;
    while(xia_y - shang_y>730 || xia_y - shang_y<670) //上下障碍随机出现的坐标范围
    {
        shang_y = rand()%400 - 550;
        xia_y = rand()%300 + 150 ;
    }
    while(gameStatus==0)      //状态为0则进入主菜单
    {
        Sleep(200);
        startMenu();//主菜单界面
        FlushBatchDraw();
    }
    mciSendString("close bkmusic_1",NULL,0,NULL);//关闭主菜单背景音乐
    mciSendString("open F:\\背景音乐2.mp3 alias bkmusic_2",NULL,0,NULL);//打开游戏背景音乐
    mciSendString("play bkmusic_2 repeat",NULL,0,NULL);//播放
    mciSendString("close beginmusic",NULL,0,NULL);
    mciSendString("open F:\\开始.mp3 alias beginmusic ",NULL,0,NULL);//播放一次开始时的预备音效
    mciSendString("play beginmusic",NULL,0,NULL);
}

//显示画面 
void show()
{
    Sleep(Difficulty);  //整体速度控制即难度
    putimage(0,0,&img_bk);  //打开背景画面
    //采用精灵图与掩码图叠加偶读方法实现抠图,让部分区域透明
    putimage(huaji_x,huaji_y,&huaji1,NOTSRCERASE);  //透明化边界外的图片
    putimage(huaji_x,huaji_y,&huaji2,SRCINVERT);    
    putimage(bar_x,shang_y,&shang1,NOTSRCERASE);//上障碍
    putimage(bar_x,shang_y,&shang2,SRCINVERT);
    putimage(bar_x,xia_y,&xia1,NOTSRCERASE);//下障碍
    putimage(bar_x,xia_y,&xia2,SRCINVERT);
    
    setbkmode(TRANSPARENT);//文字背景透明

    settextcolor(RED);
    settextstyle(50,0,_T("华文行楷"));
    outtextxy(0,0,"得分:");
    settextcolor(RED);  
    settextstyle(50,0,_T("Algerain"));//显示分数
    char s[10];
    sprintf(s,"%d",score);
    outtextxy(125,0,s);
    FlushBatchDraw();
}

//与输入有关的更新
void updateWithInput()  
{
    char input;
    if (kbhit())//判断是否有键盘输入
    {
        input = getch();
        if (input==' ')
        {   
        loadimage(&tiao1,"F:\\我跳1.jpg");
        loadimage(&tiao2,"F:\\我跳2.jpg");
        putimage(huaji_x,huaji_y,&tiao1,NOTSRCERASE);//每跳一下滑稽的表情就变一次
        putimage(huaji_x,huaji_y,&tiao2,SRCINVERT); 
        huaji_y-=30;//点一下空格滑稽就会上跳的高度

        mciSendString("close jpmusic",NULL,0,NULL);
        mciSendString("open F:\\跳.mp3 alias jpmusic ",NULL,0,NULL);//按一下空格播放一次音效
        mciSendString("play jpmusic",NULL,0,NULL);
        }
        else if(input==27)//27为esc 键的ascll码
        {
        writeRecordFile();//存档
        mciSendString("close bkmusic_2",NULL,0,NULL);//关闭游戏时的背景音乐
        pauseMenu();//打开暂停界面
        }
    }
}

//与玩家输入无关的游戏界面更新
void updateWithoutInput()
{
    if (huaji_y<High)   //自动下落
        huaji_y++;
    if (bar_x>-140)        //障碍左移,140为整个障碍的宽度
        bar_x--;
    else                   //障碍重新从右边出现
    {
        bar_x = Width;
        shang_y = rand()%300 - 450;
        while(xia_y - shang_y>730 || xia_y - shang_y<670)
        {
            shang_y =rand()%300 - 450;
            xia_y = rand()%300 + 150 ;
        }
    }
    
    if (((bar_x<50 && bar_x>-100) && (huaji_y+40>xia_y || huaji_y<shang_y+585)) || (huaji_y>550 || huaji_y<0 ))//判断失败
    {
        mciSendString("close bkmusic_2",NULL,0,NULL);//关闭背景音乐
        mciSendString("close overmusic_1",NULL,0,NULL);
        mciSendString("open F:\\尖叫.mp3 alias overmusic_1 ",NULL,0,NULL);//播放触碰危险边缘的尖叫音效
        mciSendString("play overmusic_1",NULL,0,NULL);

      loadimage(&over1,"F:\\我输了1.jpg");//还是用两图叠加的方法实现 失败时表情边缘的透明
        loadimage(&over2,"F:\\我输了2.jpg");
        putimage(huaji_x,huaji_y,&over1,NOTSRCERASE);//输了后滑稽变为 失败时 的表情
        putimage(huaji_x,huaji_y,&over2,SRCINVERT);
        FlushBatchDraw();
        Sleep(2000);//表情出现后停留一段时间

        mciSendString("close overmusic_2",NULL,0,NULL);
        mciSendString("open F:\\失败.mp3 alias overmusic_2 ",NULL,0,NULL);//播放 失败后 的背景音乐
        mciSendString("play overmusic_2",NULL,0,NULL);
        loadimage(&over3,"F:\\不要打扰我学习.jpg");//打开 失败后 的背景图片
        putimage(0,0,&over3);
        FlushBatchDraw();
        Sleep(5000);//图片出现后停留一段时间
         overMenu();
    }
         if
(bar_x==-90) //跳过障碍后加一分
         {
           score++;
           mciSendString("close score",NULL,0,NULL);
           
           mciSendString("open F:\\加一.mp3 alias score",NULL,0,NULL);//打开加分时的音效
           mciSendString("play score",NULL,0,NULL);
        }
}
//游戏结束处理
void gameOver()
{
    EndBatchDraw();//结束绘图
    closegraph();//关闭图片
}

void main()
{
    startup();              //数据初始化
    show();                 //显示画面(这一画面为准备阶段的画面)
    Sleep(1400);            //游戏准备阶段的延时
    while(1)//游戏循环执行
    {
        show();                           //再次显示画面(游戏开始玩时的界面)
        updateWithoutInput();//与玩家输入无关的游戏界面更新
        updateWithInput();//与玩家输入有光的游戏界面更新
    }
   gameOver();//游戏结束处理
}

猜你喜欢

转载自blog.csdn.net/qq_43605229/article/details/88948520