C language game (flappy bird), with source code and materials

Preface

This is the first program I wrote. I will write an article to commemorate it, and also give it a reference for subsequent students who have just started learning computers.

Note: To complete this program, you need to use the <graphics.h> data under the easy-x library. It is recommended to use software such as vc6 or vs2013 or above that supports the installation of the easy-x library. Easy-
x library installation is quite simple. See
Easy-X installation. Or
https://blog.csdn.net/qq_43605229/article/details/97611837

1. System introduction and final effect

Insert image description here
The game is called FLIP, adapted from flappy bird. The game implements the function of pressing the space bar to jump, crossing obstacles without scoring, and touching the boundaries of obstacles or the upper and lower boundaries of the game window to end the game. Among them, the interaction of pictures, sound effects, file writing/reading, keyboard input, and mouse input makes the game experience better. There are multiple modules to choose from under the main menu of the game. You can start/continue/quit the game and get help and game-related information. You can pause and return to the main menu at any time during the game or choose to continue the game. After the game is over, you can also choose to return to the main menu or restart or exit the game.
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here
Insert image description here

2. Download the function module diagram and some required materials

Function module diagram
The picture below shows the pictures and audio files I used when programming ( click here to download the materials with points ), click here to download the Baidu Cloud Disk, and extract the code 2333 (if possible, please support the points download). You don’t have to use my materials, you can Use your favorite pictures and audio files. It is recommended to put these materials in a folder for easy reference later.
Insert image description here

3. Specific code (there is a specific explanation in the code)

I am running it under VC6.0 with the easy-x library installed.

1. Header file

// #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. Global variable definition

//定义全局变量
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. Save and read files function

//读取游戏存档,实现“继续游戏”
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. About/Help menu function

//主菜单里的“帮助”界面
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. Main menu/pause menu/end menu function

//主菜单界面
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. Initialization function

//初始化
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. Other auxiliary functions

//显示画面 
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. Main function

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

4. Some image processing principles

Image processing is mainly about cutting out pictures and taking out the desired steps, emmmm, let’s take the following thing as an example.
We first find the picture we need, like the one below. I want this picture to not have the outer white border when the program is running, that is, to cut out the expression in the middle.
Then we need to use photo editing software to make the picture on the left (I made it with PS).
Here is a PS tutorial: Open photoshop, open [Image] → [Adjustment] → [Threshold] in the menu bar above, and then adjust Threshold to get the desired black and white picture, just like the picture on the left below (the part we want to cut out is white, and the part we don’t want is black)
Insert image description here

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

After processing these few lines of code, the expression we need will be drawn out in the program, and there will be no white edges around the edges.

5. Complete source code

#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();//游戏结束处理
}

Guess you like

Origin blog.csdn.net/qq_43605229/article/details/88948520