Qt项目实战:愤怒的小鸟(联机版)

前言:本文章会详细介绍难点的内容,不附带全部源码,会将关键代码进行展示。因为只有截图,这里在每一个动作和界面都添加了音效与BGM,同时附加了CG展示

素材和音效全部放在下面了,需要可自行提取。

先来看效果:

①登录界面(右上角为退出与关闭特效音乐)

Qt项目实战:愤怒的小鸟(联机版)_第1张图片

 ②注册界面

Qt项目实战:愤怒的小鸟(联机版)_第2张图片

 ③游戏界面(未设计关卡,未添加弹弓皮筋因为没找到图元,但是具有拉皮筋的音效)

右上角为游戏设置界面。

Qt项目实战:愤怒的小鸟(联机版)_第3张图片

 打中后猪类特效变化(同时猪类具有爆炸音效)

Qt项目实战:愤怒的小鸟(联机版)_第4张图片

 ④游戏设置界面。

这里没有写"继续游戏",因为太简单,只需要hide界面再show就行了。

 ⑤用户投诉与建议界面。

刚进去会播放一个MV...(这里随便添加了一个....)

Qt项目实战:愤怒的小鸟(联机版)_第5张图片

 然后会跳转至正常的客户端界面(这里没有写返回按钮,因为是拿demo给大家讲解的)

Qt项目实战:愤怒的小鸟(联机版)_第6张图片

  ⑥服务器端接收界面。(这是一个新的进程)

Qt项目实战:愤怒的小鸟(联机版)_第7张图片

 ------------------------------------------------------我是分割线----------------------------------------------------------

好的,那么接下来将详细讲解困难点的思路。(game界面可直接使用,含重力引擎)

困难点:重力引擎的定制、界面切换的管理、数据库的对接与解析。

内容讲解:

一、界面管理(客户端)

确定我们需要的界面(五个),通过信号进行切换,每一个界面有一个独特信号。每当发出信号时,在管理界面进入槽函数进行切换。

如下: 先创建【所有界面】在【管理界面】。

mange::mange(QObject *parent) : QObject(parent)
{
    Mysp =new QMediaPlayer; //按钮音效
    Mysp->setMedia(QUrl("D:/QTproject/MyQtProject/music/bird.wav"));
    StOne= new Start;//登录界面实例化
    StTwo= new zhuce;//注册界面实例化
    Game =new GAME;//游戏界面
    Setting=new setting;//设置界面
    ClientAndServer=new clietandserver;//客户端界面
   this->ClientAndServer->timer->stop();
    AllSignal();//所有的连接信号公有制函数
}

void mange::AllSignal()
{
    connect(StOne,SIGNAL(jumptozhuce()),this,SLOT(JumpToZhuce()));//登录跳注册
    connect(StTwo,SIGNAL(jumptodenglu()),this,SLOT(JumpToDenglu()));//注册跳登录
    connect(StOne,SIGNAL (jumptogame()),this,SLOT(JumpToGame()));//登录跳游戏
    connect(Game,SIGNAL(jumptosetting()),this,SLOT(JumpToSetting()));//游戏跳设置
    connect(Setting,SIGNAL(Setting_Back()),this,SLOT(JumpToDenglu())); //设置跳登录
    connect(Setting,SIGNAL(Setting_PlayAgain()),this,SLOT(JumpToGame()));//设置跳游戏
    connect(Setting,SIGNAL(Setting_Music()),this,SLOT(CloseMusic()));//设置界面里面的关闭音乐信号
    connect(Setting,SIGNAL(Setting_advice()),this,SLOT(JumpToAdvice()));//设置跳客户端
}

  
void mange::JumpToZhuce()//槽函数  【登录跳注册】
{
    Mysp->play();  //播放器 注册界面专用
    this->Setting->PLAY->stop();//停止设置界面的BGM
    this->Game->PLAY->stop();//停止游戏界面的BGM
    this->StOne->PLAY->stop();//停止登录界面的BGM
    this->StOne->close();//关闭登录界面
    this->Game->close(); //关闭游戏界面
    this->Setting->close();//关闭设置界面
    delete this->StTwo;//释放上一个注册界面,以保证进入的界面是全新的,防止内存泄漏
    this->StTwo=new zhuce;//创建新注册界面
    this->StTwo->show();  //跳转至注册界面
    this->StTwo->PLAY->play();//开启注册界面BGM
    this->ClientAndServer->timer->stop();//关闭在客户端界面的计时器(控制视频播放的计时器,在客户端界面new的时候会走构造函数激活导致视频播放,关闭其计时器保证其不影响其他函数)
    AllSignal();
}
其他的跳转和上面是一样的,删除跳转界面对象,重新创建并展示,同时停止其他的界面BGM和显示

 二、数据库单例的创建(服务器端)

数据库H文件

#ifndef NEWSQLITE_H
#define NEWSQLITE_H
#include "sqlite3.h"
#include 
#include 
#include 

class NewSQLITE
{
public:
    static  NewSQLITE* CreateS(); //创建的数据函数
    static NewSQLITE*  MySql; //与创建函数进行关联使用
    int Insert(char*sql);//插入数据操作(注册)
    int Find();//进行确定注册人数的函数
    int  Select(char*NAME,char*PWD);//登录密码与账号的检测
    sqlite3*db;
private:
    NewSQLITE();
};

#endif // NEWSQLITE_H
#include "NewSQLITE.h"
NewSQLITE* NewSQLITE::MySql=nullptr;//初始化静态数据成员
NewSQLITE::NewSQLITE() //调取函数时,直接在构造里将其打开及建表
{
    char *Message;
    int res =sqlite3_open("information.db",&db);
    if(res!=0){qDebug()<<"数据库打开失败";}
    qDebug()<<"数据库已打开";
    QByteArray sql="create table if not exists  Code( ID int primary key not null,Name text,PWD text);";
    int bc = sqlite3_exec(db, sql.data(),nullptr,nullptr,&Message);
    if(bc<0){qDebug()<<"数据表创建失败";}
    qDebug()<<"数据表已创建";
    qDebug()<<"我"<

三,游戏界面内的抛物线即重力引擎绘制(客户端)

game.h文件

#ifndef GAME_H
#define GAME_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  
#include 
#include 
#include 
#include 
#include 
#include    "pig.h"
#include "changebutton.h"

class GAME: public QWidget
{
    Q_OBJECT
public:
    explicit GAME(QWidget *parent = nullptr);
    void ChangePic();
    void  paintEvent(QPaintEvent *event);
    void  mouseMoveEvent(QMouseEvent *event);
    void TreePic();
    void TreePic2();
    void  mouseReleaseEvent(QMouseEvent*event);
    void  GradePic(int LEFT);
    void CreatePig();
public:
    int x,y;   int jisuan=0; //计算
    int flag= 1;   int LEFT=3; //生命下标
    float  Q; float Z=1; float S;//物理引擎系数
    QMediaPlayer * PLAY;//界面BGM
    QMediaPlayer*  Temp;//音效
    QMediaPlayer* BOOMMUSIC;//猪爆炸音效
    QMediaPlayer* DanMUSIC;//弹弓拉伸音效
    changebutton *SET;//右上角的设置按钮图片
    QTimer timer1;//开头直接激活,将鸟从地面飞到弹弓上
    QTimer timer2;//鼠标松开后,进行鸟飞翔位置移动定时器
    QTimer timer3;//分数实时计算的计时器
    QTimer timer4;//碰撞检测定时器
    QPixmap *pix;//鸟
    QPixmap *pixtree;//右边的树
    QPixmap *lpixtree;//左边的树2
    QLabel* Grade;//实时生命值
    QLabel *Pic;//实时刷新的图片
    QLabel*bird; 
    QLabel* tree;
    QLabel* tree2;
    QLabel* Tip;
    QLabel *Pig1;
    QLabel *Pig2;
    QLabel *Pig3;
    QLabel *Pig4;
public:
    pig*A1; pig*A2; pig*A3;pig*A4;//猪类指针(此类规定猪的图片大小)
signals:
    void backtodenglu();
    void jumptosetting();
public slots:
    void ReGo();
    void  JumpTree();
    void  SHowGrade();
    void   BOOM();
  void GOSetting();
};

#endif // GAME_H

 game.cpp文件

#include "GAME.h"

GAME::GAME(QWidget *parent) : QWidget(parent)
{
    setFixedSize(1500,800);
    x=160; y=660;//初始化鸟的位置
    timer1.start(10);   //起始跳位置
    setGeometry(70,50,1500,800);  //建立界面最大长度和初始长度
    this->setWindowIcon(QIcon(":/photo/redbird.webp"));
    this->setWindowTitle("愤怒的小鸟");
    SET=new changebutton(this);
    Grade=new QLabel(this);//生命标签
    Pic=new QLabel(this);    //插图标签
    Tip=new QLabel(this);//分数标签
    PLAY=new QMediaPlayer;
    Temp=new QMediaPlayer;
    BOOMMUSIC=new QMediaPlayer;
    DanMUSIC=new QMediaPlayer;
    Pig2= new QLabel(this);
    Pig3= new QLabel(this);Pig4= new QLabel(this);
    Pig1= new QLabel(this);
    PLAY->setMedia(QUrl("D:/QTproject/MyQtProject/music/BGMjiemian.mp3"));
    SET->setStyleSheet("border-image:url(:/photo/设置图标.png)");
    SET->setGeometry(1395,28,40,40);
    TreePic();//树的右边
    CreatePig();
    ChangePic();//鸟类的图源定制及初始位置
    TreePic2();//树的左边
    connect(&timer1,SIGNAL(timeout()),this,SLOT(JumpTree()));
    connect(&timer2,SIGNAL(timeout()),this,SLOT(ReGo())) ;
    connect(&timer3,SIGNAL(timeout()),this,SLOT(SHowGrade()));
    connect(&timer4,SIGNAL(timeout()),this,SLOT(BOOM()));
    connect(SET,SIGNAL(clicked()),this,SLOT(GOSetting()));
    GradePic(LEFT); //创建生命
    SHowGrade(); //创建分数
}

void GAME::paintEvent(QPaintEvent *event)
{
    if(event == nullptr) {qDebug()<<"event";}
    QPainter A(this);
    A.drawPixmap(0,0,1500,800,QPixmap(":/photo/Gamejiemian.png"));
    GradePic(LEFT);
}

void  GAME::ChangePic() //鸟类的图源定制及初始位置
{
    bird=new QLabel(this);
    pix=new QPixmap;
    this->pix->load(":/photo/bird.png");//下载红鸟图片源文件
    *pix = pix->scaled(pix->width() * 0.8, pix->height() * 0.8);//将图片调整为大小0.8
    this->bird->setPixmap(*pix);

}

void GAME::TreePic()//右边弹弓的图元定制
{
    tree=new QLabel(this);
    pixtree=new QPixmap;
    this->pixtree->load(":/photo/dangong1 (1).png");//下载右弹弓图片源文件
    *pixtree = pixtree->scaled(pixtree->width(), pixtree->height()*0.7);//将图片调整为大小0.8
    this->tree->setPixmap(*pixtree);
    this->tree->move(330,556);
}

void GAME::TreePic2()
{
    tree2=new QLabel(this);
    lpixtree=new QPixmap;
    this->lpixtree->load(":/photo/dangong2.png");//下载右弹弓图片源文件
    *lpixtree = lpixtree->scaled(lpixtree->width(), lpixtree->height()*0.7);//将图片调整为大小0.8
    this->tree2->setPixmap(*lpixtree);
    this->tree2->move(300,551);
}

void GAME::JumpTree()
{
    this->bird->move(x,y);
    if(x<=318||y>=558)
    {
        x=x+3; y=y-2;
        this->bird->move(x,y);
        update();
    }
    else if(x>318)
    {
        timer1.stop();
    }
}

void GAME::SHowGrade()//计算分数的内容
{
    int F=this->x; int  C=this->y;
    QString N=QString("单次飞跃分数:")+QString::number((F*C)-105600);
    Tip->setFixedSize(300,30);
    Tip->setText(N);
    // Tip->setScaledContents(true);
    Tip->setStyleSheet("font:78 15pt Bodoni MT");
    Tip->move(0,40);
    int BB=this->jisuan;
    QString Temp = Tip->text();
    int CC=Temp.toInt();
    int FF =BB+CC;
    this->jisuan=FF;
}

void GAME::mouseReleaseEvent(QMouseEvent *event)//启动分数、移动定时器
{
    if(event->x()>50&&event->x()<350&&event->y()<660&&event->y()>460)
    {
        QString  W =QString::number(event->x());
        QString  Y=QString::number(event->y());
        qDebug()<<"W=="<x =W.toFloat();  this->y=Y.toFloat();
        if(x>50&&x<350&&y<660&&y>460)//第三象限
        {

            Temp->setMedia(QUrl("D:/QTproject/MyQtProject/music/bird.wav"));
            Temp->play();
            this->Q=  ( (250-x)+(y-556) )/25; //初始飞行系数
            this->Z =(Q/0.8);//递减飞行系数
            this->S = Z-Q;
            timer2.start(10);//飞行定时器
             timer3.start(10);//飞行定时器
            timer4.start(10);//碰撞定时器
        }
    }
}

void GAME::mouseMoveEvent(QMouseEvent *event)//鼠标移动并按下的事件
{
    if(event->x()>50&&event->x()<350&&event->y()<660&&event->y()>460)
    {
        QString  W =QString::number(event->x());
        QString  Y=QString::number(event->y());
        this->x =W.toInt();  this->y=Y.toInt();
        if(event->buttons()==Qt::LeftButton)
        {
            if(x>50&&x<350&&y<660&&y>460&&timer1.isActive()==false)
            {
                DanMUSIC->setMedia(QUrl("D:/QTproject/MyQtProject/music/LGMusic.wav"));
                DanMUSIC->play();
                this->bird->move(x,y);
                qDebug()<<"x=="<=50&&y<=660&&timer1.isActive()==false)
    {

        qDebug()<<"Q=="<0){S +=0.1;}
        if(flag>10)
        {
            this->x += S; //横向飞行速度
            this->y -= Z;  //纵向飞行速度
            Z -=0.1;
        }
        else if(flag<=10)
        {
            this->x += S; //横向飞行速度
            this->y -= Z;  //纵向飞行速度
        }
        qDebug()<<"X=="<bird->move(x,y);
        update();
        if(this->y>=661)
        {
            if(this->LEFT ==1)
            {
                QMessageBox  Grade;
                Grade.information(this,"游戏结束","您的手法和蔡徐坤一样菜",QMessageBox::Yes);
                emit jumptosetting();

            }
            else
            {
                qDebug()<<"timer111";
                Sleep(1500);
                this->x=160;
                this->y=660;//重置
                this->LEFT--;
                timer2.stop();
                timer3.stop();
                timer1.start(8);
                qDebug()<<"11";
            }
        }

    }
}

void GAME::GradePic(int SS)
{
    Grade->setStyleSheet("font:75 15pt Bodoni MT");
    if(SS==2)
    {
        QString A=QString("剩余生命值:")+QString::number(SS-1);
        Grade->setText(A);
        Pic->setPixmap(QPixmap(":/photo/dangong1 (10).png"));
    }
    else if (SS==3)
    {    QString A=QString("剩余生命值:")+QString::number(SS-1);
        Grade->setText(A);
        Pic->setFixedSize(25,25);
        Pic->setScaledContents(true);
        Pic->setPixmap(QPixmap(":/photo/bird.png"));
    }
    else if(SS==1)
    {    QString A=QString("剩余生命值:")+QString::number(SS-1);
        Grade->setText(A);
        Pic->setPixmap(QPixmap(":/photo/dangong1 (9).png"));
    }
    Grade->move(5,0);//鸟
    Pic->move(155,2);
    update();
}

void GAME::CreatePig()
{
    A1=new pig(this); A1->move(1300,655);
    A2=new pig(this); A2->move(1340,305);
    A3=new pig(this); A3->move(1060,405);
    A4=new pig(this); A4->move(1160,505);
}

void GAME::GOSetting()
{
    PLAY->stop();
    emit  jumptosetting();
}

void GAME::BOOM()
{
    if(x>A1->x()-20&&x<(A1->x()+30))
    {
        if(this->y>A1->y()-20&&this->yy()+20)
        {
            if(this->A1->isVisible());
            {
                BOOMMUSIC->setMedia(QUrl("D:/QTproject/MyQtProject/music/BOOM.mp3"));
                BOOMMUSIC->play();
                this->A1->hide();
                Pig1->setPixmap(QPixmap(":/photo/dangong1 (11).png"));
                Pig1->setGeometry(A1->x(),A1->y(),50,50);

            }
        }
    }
    else  if(x>A2->x()-20&&x<(A2->x()+30))
    {
        if(this->y>A2->y()-30&&this->yy()+30)
        {
            if(this->A2->isVisible())
            {
                BOOMMUSIC->setMedia(QUrl("D:/QTproject/MyQtProject/music/BOOM.mp3"));
                BOOMMUSIC->play();
                qDebug()<<"111";
                this->A2->hide();
                Pig2->setPixmap(QPixmap(":/photo/dangong1 (11).png"));
                Pig2->setGeometry(A2->x(),A2->y(),50,50);
            }
        }
    }
    else  if(x>A3->x()-30&&x<(A3->x()+30))
    {
        if(this->y>A3->y()-30&&this->yy()+30)
        {
            if(this->A3->isVisible())
            {
                BOOMMUSIC->setMedia(QUrl("D:/QTproject/MyQtProject/music/BOOM.mp3"));
                BOOMMUSIC->play();
                this->A3->hide();
                Pig3->setPixmap(QPixmap(":/photo/dangong1 (11).png"));
                Pig3->setGeometry(A3->x(),A3->y(),50,50);
            }
        }
    }
    else  if(x>A4->x()-20&&x<(A4->x()+30))
    {
        if(this->y>A4->y()-30&&this->yy()+30)
        {
            if(this->A4->isVisible())
            {
                BOOMMUSIC->setMedia(QUrl("D:/QTproject/MyQtProject/music/BOOM.mp3"));
                BOOMMUSIC->play();
                qDebug()<<"111";
                this->A4->hide();
                Pig4->setPixmap(QPixmap(":/photo/dangong1 (11).png"));
                Pig4->setGeometry(A4->x(),A4->y(),50,50);
            }
        }
    }
}

此GAME类的源码可直接使用打开QT中,但要记得改pro内容以获得播放器播放的权限。

保持如下:

QT += multimedia
QT       += core gui network
QT += multimediawidgets
QT += multimedia multimediawidgets

服务器和客户端的搭建就不过多阐述了,简单说一下。服务器是一个单独的内容,用来接收用户的使用需求,IP和端口号是绑死的。

客户端是用户端的内容。

----------------------------------------我是分割线-----------------------------------------------------------------

吃透了上面三个内容,这个游戏就会很简单,里面的素材与音效放在下面啦。

百度网盘链接:https://pan.baidu.com/s/1gQRzcs0Q1c-QrNiudYh03w 
提取码:1g2c

Qt项目实战:愤怒的小鸟(联机版)_第8张图片

Qt项目实战:愤怒的小鸟(联机版)_第9张图片

你可能感兴趣的:(qt,开发语言)