前言

本文章主要讲解我和朋友一起用Qt开发的小游戏《愤怒的小鸟》,游戏素材来源于游戏截图和网上查找。这是一款曾经在手机上风靡一时的横屏小游戏,游戏具体怎么玩想必我就不用跟大家介绍了吧。主要说说里面最不好实现的一个东西:“物理引擎”,就是小鸟的飞行轨迹和小鸟和障碍物的撞击效果。

一、游戏效果

​​​​在这里插地方入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、代码功能模块

1.第一个模块(主模块) 登录界面

核心代码如下(示例):

void Widget::regiser(bool)
{
    //查询用户是否已经存在
    QString  str = QString("select * from usertable where account='%0';")\
                                        .       arg(le_account->text());
    QSqlQuery query;
    query.exec(str);
    while(query.next())
    {
        QMessageBox msgBox;
        msgBox.setText("该用户已存在!请重新注册!");
        msgBox.exec();
        return ;
    }
    //不存在就注册
    bool ok;
    QString username = QInputDialog::getText(this, "Angry Birds",
                                               "User name:",QLineEdit::Normal,QDir::home().dirName(),
                                                &ok);

    if (ok && !username.isEmpty())
    {
        //向入据库中加入一条用户信息
        QString  str = QString("insert into usertable values('%0', '%1', '%2', '0');")\
                                .arg(le_account->text()).arg(le_password->text()).arg(username);//插入用户 账号,密码,用名
        QSqlQuery query;
        query.exec(str);

        QMessageBox msgBox;
        msgBox.setText("恭喜你!注册成功!");
        msgBox.exec();
    }
}
void Widget::login(bool)
{
    //账号√ 密码√
    QString  str = QString("select * from usertable where account='%0' and password='%1';")\
                                        .arg(le_account->text()).arg(le_password->text());
    QSqlQuery query;
    query.exec(str);
    while(query.next())
    {
        qDebug() << query.value(0).toString();
        qDebug() << query.value(1).toString();
        qDebug() << query.value(2).toString();
        qDebug() << query.value(3).toString();
        emit login_successed();//发射登录成功的信号
        hide();//隐藏当前界面
        return ;
    }
    //账号√密码×
    str = QString("select * from usertable where account='%0';")\
                                        .arg(le_account->text());
    query.exec(str);
    while(query.next())
    {
        QMessageBox msgBox;
        msgBox.setText("密码错误!请重新输入!");
        msgBox.exec();
        return ;
    }
    //账号x
    QMessageBox msgBox;
    msgBox.setText("该用户不存在!请先注册!");
    msgBox.exec();
}

2.第二个模块 游戏开始界面

核心代码如下(示例):

Start::Start(QWidget *parent) : QWidget(parent)
{
    setFixedSize(1800,967);
    setGeometry(70,50,1800,967);
    this->setWindowIcon(QIcon(":/img/icon.png"));
    this->setWindowTitle("愤怒的小鸟");
    //界面跳转
    choose = new choosepoint;
    connect(this, &Start::start, this, [&](){
        choose->setGeometry(this->geometry());
                choose->show();
    });//绑定当前界面 发射的start开始游戏的信号 给选择关卡界面choose 让它显示
    connect(choose, &choosepoint::choosesceneback, this, [&](){
        this->setGeometry(choose->geometry());
                this->show();
    });//绑定choose选择关卡界面 发射的choosesceneback返回信号 给当前界面 让它显示
    /*connect(choose, &choosepoint::choosesceneback, [=](){//绑定choose选择关卡界面 发射的choosesceneback返回信号 给当前界面 让它显示
        choose->hide();
        this->show();
    });*/
}
void Start::paintEvent(QPaintEvent *event)
{
    QPainter p(this);
    p.drawPixmap(0, 0, 1800, 967, QPixmap(":/img/start.jpg"));
    p.drawPixmap(1713, 10, 77, 32, QPixmap(":/img/BackButton.png"));
}
void Start::mousePressEvent(QMouseEvent *event)
{
    //点击密码的显示与隐藏
    if(event->pos().x() > 760 && event->pos().x() < 1040 && event->pos().y() > 510 && event->pos().y() < 640)
    {
        emit start();
        hide();//隐藏当前界面
    }
    if(event->pos().x() > 1713 && event->pos().x() < 1790 && event->pos().y() > 10 && event->pos().y() < 42)
    {
        emit back();
        hide();//隐藏当前界面
    }
}

3.第三个模块 关卡选择界面

choosepoint::choosepoint(QWidget *parent) : QMainWindow(parent)
{
    //选择关卡场景
    this->setFixedSize(1800, 967);
    setGeometry(70,50,1800,967);
    this->setWindowIcon(QIcon(":/img/icon.png"));
    this->setWindowTitle("关卡场景");
    //返回按钮
    mybushbutton * backbtn = new mybushbutton(":/img/BackButton.png",":/img/BackButtonSelected.png");

    backbtn->setParent(this);
    backbtn->move(1713, 10);
    //跳转到上一个界面
    connect(backbtn, &mybushbutton::clicked,[=](){
            QTimer::singleShot(300,this,[=](){
            emit this->choosesceneback(); //为了看到动画效果
            hide();
        });
    });
    int i;
    //跳转到关卡界面   创建选择关卡的按钮
    for( i = 0; i < 20; i++)
    {
        mybushbutton * menubtn = new mybushbutton(":/img/LevelIcon.png");

        menubtn->setParent(this);
        menubtn->move( 560 + i % 5 * 160, 300 + i / 5 * 130);  //一维数构造二维数组

        connect(menubtn, &mybushbutton::clicked,[=](){

               this->hide();//隐藏当前界面
                //界面跳转
                shot = new slingshot(i + 1);
                shot->setGeometry(this->geometry());
                shot->show();
                //设置游戏场景初始位置
                //监听返回
        connect(shot, &slingshot::back, this, [=](){

                this->setGeometry(shot->geometry());

                shot->deleteLater();
                this->show();

            });//
        });
        QLabel * label = new QLabel;
        label->setParent(this);
        label->setFixedSize(menubtn->width(),menubtn->height());
        label->setText(QString::number(i+1));
        label->move(560 + i % 5 * 160, 300 + i / 5 * 130);

        //设置label上的文字对齐方式
        label->setAlignment(Qt::AlignHCenter | Qt:: AlignVCenter);
        //设置鼠标穿透事件  51号
        label->setAttribute(Qt::WA_TransparentForMouseEvents);
    }

}
//重写绘图事件
void choosepoint::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QPixmap pix;
    //加载图片
    pix.load(":/img/choose.jpg");
    painter.drawPixmap(0,0,this->width(),this->height(),pix);
}

4.第四个模块 游戏界面

void slingshot::mouseMoveEvent(QMouseEvent *event)
{
    //判断拉动皮筋
    if(event->pos().x() > 440 && event->pos().x() < 490 && event->pos().y() > 546 && event->pos().y() < 556)
        pullflag = true;
    if(pullflag && event->pos().x() >0 && event->pos().x() < 900 && event->pos().y() > 0 && event->pos().y() < 967)
        posline = event->pos();
    update();
}
void slingshot::mouseReleaseEvent(QMouseEvent *event)
{
    //判断在拉动皮筋后松开皮筋
    if(pullflag)
    {
        emit Releaseline();
        check->b->current_vx = check->b->current_vy = 0;
        vx = 465 - posline.x();
        vy = 551 - posline.y();
        resistance_const = 0.0003;
        accg = -30.6;
        qDebug() << 465 - posline.x() << 551 - posline.y() << "hhhhh";
        posline = QPoint(465, 551);
        pullflag = false;
    }
    update();
}
void slingshot::mousePressEvent(QMouseEvent *event)
{
    //退出游戏
    if(event->pos().x() > 1740 && event->pos().x() < 1790 && event->pos().y() > 10 && event->pos().y() < 60)
    {
          QMessageBox msgBox;
          msgBox.setText("你确定要退出游戏吗?");
          msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
          if( QMessageBox::Yes == msgBox.exec())
          {
              emit back();
              hide();//隐藏当前界面
          }
    }
}

void slingshot::slig(QPoint p)
{
    //判断拉动皮筋
    if(p.x() > 440 && p.x() < 490 && p.y() > 546 && p.y() < 556)
        pullflag = true;
    if(pullflag && p.x() >100 && p.x() < 763 && p.y() > 240 && p.y() < 840)
        posline = p;
    update();
}

5.第五个模块 鸟对象

void bird::port(qreal vx, qreal vy, qreal resistance_const, qreal accg)
{
    if(current_vy == 0 && current_vx == 0 && time == 0)
    {

        current_vx = vx;
        current_vy = vy;
        this->resistance_const = resistance_const;
        this->accg = accg;

    }

   if(time == 0)
   {
        wpos = this->geometry().topLeft();
        track_x = track_y = 0;
   }

    resistance_ax = resistance_const * current_vx * current_vx / bird_weight;
    //resistance_ay = resistance_const * current_vy * current_vy / bird_weight;
    //qDebug() << resistance_ax << "ax";


    last_vx = current_vx;
    current_vx -= (resistance_ax + 0.4 * 0.01);

    if(flag == true)
    {
        current_vy +=  (accg * 0.1 + 2);
        energy -= (accg * 0.1 + 2);
        if(energy < 0)
            flag = false;
    }else
    {
        current_vy -=  (accg * 0.1 - 2);
        energy += (accg * 0.1 - 2);
        if(current_vy < 0)
            flag = true;
    }


    if( qAbs(current_vx + last_vx) != qAbs(qAbs(current_vx) + qAbs(last_vx)) ) //单位统一
    {
        vx_flag = false;
    }

    time += 0.1;


    qDebug() << current_vx << "vx";
    qDebug() << current_vy << "vy";
    if(vx_flag == true) //
    {
        track_x += current_vx * 0.1;
        //track_x = vx * time - 1/2.0 * resistance_ax * time * time - 0.2 * time *time * time;
    }
        //last_y = track_y;
        track_y += current_vy * 0.1;
        //track_y = vy * time - 1/2.0 * accg * time * time ;



    //emit bird_move(track_x, track_y);


    qDebug() << wpos.x() + track_x << wpos.y() + track_y;
    move(wpos.x() + track_x , wpos.y() + track_y );
    if(wpos.x() + track_x > 1800 || wpos.y() + track_y  > 967 || wpos.y() + track_y < 0 ||
            wpos.x() + track_x < 0 || (current_vx == 0 && current_vy == 0  ))
    {
        //move(wpos);
        move(10 , 600);
        timer->stop();
        time = 0;
        track_x = track_y = 0;
    }
    emit bird_move(QPoint(geometry().topLeft().x() + width()/2,
                          geometry().topLeft().y() + height()/2));


}

void bird::mouseMoveEvent(QMouseEvent *event)
{

    //move(event->globalX() - pos.x(), event->globalY() - pos.y());

    pos1 = event->globalPos();
//    qDebug() << "pos1" << pos1.x() << pos1.y();
//    qDebug() << "pos" << pos.x() << pos.y();
//    qDebug() << "wpos" << wpos.x() << wpos.y();
    //qDebug() << wpos.x()+pos1.x()-pos.x() << wpos.y()+pos1.y()-pos.y() << "mouse";

    move(wpos.x()+pos1.x()-pos.x(),
         wpos.y()+pos1.y()-pos.y());
    emit bird_move(QPoint(geometry().topLeft().x() + width()/2,
                          geometry().topLeft().y() + height()/2));
//    qDebug() <<  "x " << geometry().topLeft().x() + width()/2 <<
//             "y" << geometry().topLeft().y() + height()/2;

}

void bird::mousePressEvent(QMouseEvent *event)
{

    pos = event->globalPos();
    wpos = this->geometry().topLeft();

    if(event->buttons() ==  Qt::RightButton)
    {
        //emit botton_clicek(50);
        current_vx = current_vy = 0;
    }
   // pos = event->pos();

}

void bird::paintEvent(QPaintEvent *event)
{
    QPainter p(this);

    p.drawPixmap(0, 0, *pix);

}


总结

`本文章尚未完成,期待作者后续补充更改。。。。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐