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

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

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

先来看效果:

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

 ②注册界面

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

右上角为游戏设置界面。

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

 ④游戏设置界面。

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

 ⑤用户投诉与建议界面。

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

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

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

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

好的,那么接下来将详细讲解困难点的思路。(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 <QDebug>
#include <QMessageBox>
#include <QDebug>

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()<<"我"<<bc;

}
int  NewSQLITE::Insert(char*sql)//将传递的sql进行插入数据库操作
{
    char*mess;
      qDebug()<<"sql=="<<sql;
    int tc =sqlite3_exec(db,sql,nullptr,nullptr,&mess);
    qDebug()<<"我是"<<tc;
    return tc;
}

NewSQLITE* NewSQLITE::CreateS()//得到数据库实例化对象的单例函数
{
    if(NewSQLITE::MySql==nullptr)
    {
        NewSQLITE::MySql=new NewSQLITE;
    }
    return  NewSQLITE::MySql;
}

int  NewSQLITE::Find()//查询目前数据库的注册人数,并返回行数
{
      char sql[80]={0};
      sprintf(sql, "select  *from  Code;");
      char** qresult = nullptr; int row = 0; int col = 0; char*messg=nullptr;
      int  fc = sqlite3_get_table(db, sql, &qresult, &row, &col, &messg);
      qDebug()<<"右边fc=="<<fc;
      return row;
}

int NewSQLITE::Select(char *NAME, char *PWD)//检测输入的密码与pwd在数据库是否存在,返回查询的行数
{
    char sql[80]={0};
    sprintf(sql, "select  *from  Code where  Name='%s' and PWD='%s';",NAME,PWD);
    qDebug()<<sql;
   char** qresult = nullptr; int row = 0; int col = 0; char*messg=nullptr;
    int tc=sqlite3_get_table(db, sql, &qresult, &row, &col, &messg);
   qDebug()<<"特定查询row=="<<row<<"tc=="<<tc;
   return row;
}

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

game.h文件

#ifndef GAME_H
#define GAME_H
#include <QWidget>
#include <QIcon>
#include <QWidget>
#include <QPixmap>
#include <QPainter>
#include <QEvent>
#include <QDebug>
#include <QMessageBox>
#include <QMediaPlayer>
#include  <QTimer>
#include <QLabel>
#include <QPushButton>
#include <QMouseEvent>
#include <QTime>
#include <windows.h>
#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=="<<W;
        this->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=="<<x;
                qDebug()<<"y=="<<y;

            }
            else
            {
                qDebug()<<"x=="<<x;
                qDebug()<<"y=="<<y;
            }
        }
    }
}
void GAME::ReGo() //第三象限触发
{
    if(x>=50&&y<=660&&timer1.isActive()==false)
    {

        qDebug()<<"Q=="<<Q;
        qDebug()<<"Z=="<<Z;
        qDebug()<<"S=="<<S;
        flag++;
        if(S>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=="<<x;
        qDebug()<<"Y=="<<y;
        this->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->y<A1->y()+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->y<A2->y()+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->y<A3->y()+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->y<A4->y()+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和端口号是绑死的。

客户端是用户端的内容。

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

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

百度网盘链接:百度网盘 请输入提取码
提取码:1A2B

  • 6
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Qt是一个跨平台的C++应用程序开发框架,具有良好的可扩展性和易于使用的特点。而CSDN是一个国内知名的技术社区,提供了大量的编程教程和经验分享。 Qt项目实战CSDN可以是一个关于Qt开发的教程或者项目案例分享。在这个项目中,我会结合Qt的特点,通过撰写一系列的技术文章或者视频教程,详细介绍如何使用Qt进行应用程序的开发。 在这个项目中,我会从安装Qt开始,讲解Qt的基础知识,如界面设计、信号与槽机制、Qt对象模型等。然后,我会介绍Qt的高级特性,比如网络编程、数据库操作、多线程等。通过这些文章或者教程,读者可以系统地学习Qt的各个方面,从而快速掌握Qt的开发技巧。 同时,为了更好地帮助读者理解和学习Qt,我会结合实际的项目案例,展示如何使用Qt进行实际应用的开发。具体案例可以涵盖不同的领域,比如一个简单的音乐播放器、一个图像处理应用、一个聊天程序等。通过这些案例,读者可以更好地理解Qt的实际应用场景,并且通过参考案例代码,快速上手Qt的开发。 除了撰写技术文章或者制作视频教程,我还会积极参与到CSDN的技术社区中,回答读者的问题,与他们交流经验。这样可以进一步提升读者对于Qt开发的理解,并且根据读者的反馈,不断优化项目内容,使之更加符合读者的需求。 通过Qt项目实战CSDN,我希望能够帮助更多的开发者掌握Qt的开发技巧,实现自己的应用想法。同时,也希望能够通过与读者的交流,不断提升自己的技术水平,共同促进技术的发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值