Qt之塔防游戏 c++ (三)

在上两篇文章中,我们实现了一个简单的塔防游戏,但是游戏功能还比较单一。接下来,我们对该塔防游戏进行优化,让它有更多的功能。

在本篇文章中我们要完成如下功能:
1:实现多样化选择防御塔
2:对防御塔进行升级和移除
3:实现多关卡的绘制,供玩家选择
4:细微处的完善

我们开始吧!

实现多样化选择防御塔
要实现选择防御塔,我们要先构造一个选择框,即完成selectButton类。

先添加selectButton类文件
selectButton.h中的实现:

#ifndef SELECTBUTTON_H
#define SELECTBUTTON_H

#include <QPainter>
#include <QString>
#include <QPoint>
#include <QSize>

#include "mainwindow.h"

class MainWindow;

class selectButton
{
public:
    selectButton(QPoint pos,MainWindow * game);
    ~selectButton();
    
    void draw(QPainter * painter)const;//绘画选择框
    void getRemoved();//选择框被点击了以后,就要被移除
    bool containPos(QPoint pos);//判断鼠标的点击点,是否在选择框的内部
    QPoint getPos();//得到选择框的左上店
private:
    MainWindow * m_game;//指向mainwindow的指针
    QPoint m_pos;//selectButton图片的左上角
    QString m_selectBoxImagePath[3];//用来储存选择框内的防御塔的图片,我设置的三个防御塔可以选择,就储存三张图片
    
    static const QSize m_fixedSize;
};
#endif // SELECTBUTTON_H

同时,在TowerPosition.h中进行相应的添加:

//类外
#include "selectbutton.h"

class selectButton;
//类内
public:
    bool hasButton();//判断该位置有没有button
    void setHasButton(bool hasButton=true);//设置是否有button
    void setButton(selectButton * button);//设置button
    selectButton * getButton();//得到该位置的button
    
    bool hasTower1();//判断是否有第一种塔
    void setHasTower1(bool hasTower1=true);//判断是否有第一种塔
    
    bool hasTower2();
    void setHasTower2(bool hasTower2=true);
    
    bool HasTower3();
    void setHasTower3(bool hasTower3=true);
private:
    bool m_hasButton;
    bool m_hasTower1;
    bool m_hasTower2;
    bool m_hasTower3;

    selectButton * m_button;//私有化button

TowerPosition.cpp中对其进行实现:

//构造函数中添加:
    m_hasTower1(false),
    m_hasTower2(false),
    m_hasTower3(false),
    m_hasButton(false)

//其他函数
bool TowerPosition::hasButton()
{
    return m_hasButton;
}

void TowerPosition::setHasButton(bool hasButton)
{
    m_hasButton=hasButton;
}

void TowerPosition::setButton(selectButton *button)
{
    m_button=button;
}

selectButton * TowerPosition::getButton()
{
    return m_button;
}

void TowerPosition::setHasTower1(bool hasTower1)
{
    this->m_hasTower1=hasTower1;
    setHasTower(hasTower1);
}


bool TowerPosition::hasTower1()
{
    return m_hasTower1;
}

void TowerPosition::setHasTower2(bool hasTower2)
{
    this->m_hasTower2=hasTower2;
    setHasTower(hasTower2);
}

bool TowerPosition::hasTower2()
{
    return m_hasTower2;
}

void TowerPosition::setHasTower3(bool hasTower3)
{
    m_hasTower3=hasTower3;
    setHasTower(hasTower3);
}

bool TowerPosition::hasTower3()
{
    return m_hasTower3;
}

然后到mainwindow.h中,添加有关button的代码:

//类外
#include "selectbutton.h"
class selectButton;

//类内
public:
    bool canBuyTower();//判断是否可以买第一种塔,这个我们原来已经写过了
    bool canBuyTower2();//判断是否可以买第二种塔
    bool canBuyTower3();//判断是否可以买第三种塔
    void removeButton(selectButton * button);//在mainwindow中对button进行移除
private:
    QList<selectButton * > m_selectButtonList;//用来储存selectButton的list

mainwindow.cpp中对上面的代码进行实现:

#include "selectButton"

bool MainWindow::canBuyTower2()
{
    if(m_playerGlod>=400)
    {
        return true;
    }
    return false;
}

bool MainWindow::canBuyTower3()
{
    if(m_playerGlod>=500)
    {
        return true;
    }
    return false;
}

void MainWindow::removeButton(selectButton *button)
{
    m_selectButtonList.removeOne(button);
}

ok,我们已经把button和其他的类做了一个连接,现在我们返回selectButton.cpp中,对selectButton类进行实现:

#include "selectbutton.h"

const QSize selectButton::m_fixedSize(105,35);

selectButton::selectButton(QPoint pos,MainWindow * game):
    m_game(game),
    m_pos(pos)
{
    //三张图片的路径信息 
    m_selectBoxImagePath[0]=":/images/tower1.jpg";
    m_selectBoxImagePath[1]=":/images/tower2.png";
    m_selectBoxImagePath[2]=":/images/tower3.png";
}

selectButton::~selectButton()
{
    m_game=NULL;
}

void selectButton::draw(QPainter *painter) const
{
    painter->save();
    painter->drawPixmap(m_pos.x(),m_pos.y(),m_selectBoxImagePath[0]);
    painter->drawPixmap(m_pos.x()+35,m_pos.y(),m_selectBoxImagePath[1]);
    painter->drawPixmap(m_pos.x()+70,m_pos.y(),m_selectBoxImagePath[2]);
    painter->restore();
}

void selectButton::getRemoved()
{
    m_game->removeButton(this);
}

bool selectButton::containPos(QPoint pos)
{
    bool xInhere=pos.x()>m_pos.x() && pos.x()<m_pos.x()+m_fixedSize.width();
    bool yInhere=pos.y()>m_pos.y() && pos.y()<m_pos.y()+m_fixedSize.height();
    return xInhere && yInhere;
}

QPoint selectButton::getPos()
{
    return this->m_pos;
}

现在对mainwindow.cpp中的mousePressEvent()进行改造使其能够完成防御塔的选择,在此之前,为了实现不同防御塔的不同图片,我们需要回到tower.h中,把tower的构造函数修改成:

Tower(QPoint pos,MainWindow * game,QString path,int damage);

同时在tower.cpp中,构造函数的实现也需要相应的修改,我只截取出修改的部分:

Tower::Tower(QPoint pos,MainWindow * game,QString path,int damage):
    m_attacking(false),
    m_damage(damage),

现在可以对mousePressEvent()进行改造啦,实现多样化防御塔的选择。

改造后的mousePressEvent()的while循环内部:

while(it!=m_towerPositionList.end())//遍历所有的防御塔坑
    {
        if(Qt::LeftButton==event->button())//如果是鼠标左键点击
        {
            if(!it->hasButton() && it->ContainPos(pressPos) && !it->hasTower())//如果没有button,点击的点在防御塔坑的内部
            {
                QPoint tmp(it->getPos().x()-35,it->getPos().y()-35);//得到该防御塔坑处的button的左上点
                selectButton * button=new selectButton(tmp,this);//创建一个button
                it->setHasButton(true);//设置该位置有button
                it->setButton(button);//设置该位置的button
                m_selectButtonList.push_back(button);//把这个button加入到mainwidnow中
                update();
                break;
            }
            else if(it->hasButton() && it->getButton()->containPos(pressPos) && !it->hasTower())//如果这个位置有button,并且没有防御塔
            {
                if(pressPos.x()<it->getButton()->getPos().x()+35 && canBuyTower())//如果鼠标点击的地方在第一张图片内,创造第一个防御塔
                {
                    it->setHasTower1(true);
                    m_playerGlod-=tower1Cost;
                    QString path=":/images/tower1.jpg";
                    Tower * tower=new Tower(it->getCenterPos(),this,path,10);//攻击力为10的第一种防御塔
                    m_towerList.push_back(tower);
                }
                else if(pressPos.x()>it->getButton()->getPos().x()+35 && pressPos.x()<it->getButton()->getPos().x()+70
                        && canBuyTower2())//鼠标点击点在第二张图片内,创建第二种防御塔
                {
                    it->setHasTower2(true);
                    m_playerGlod-=tower2Cost;
                    QString path=":/images/tower2.png";
                    Tower * tower=new Tower(it->getCenterPos(),this,path,15);//攻击力为15的第二种防御塔
                    m_towerList.push_back(tower);
                }
                else if(pressPos.x()>it->getButton()->getPos().x()+70 && pressPos.x()<it->getButton()->getPos().x()+105
                        && canBuyTower3())
                {
                    it->setHasTower3(true);
                    m_playerGlod-=tower3Cost;
                    QString path=":/images/tower3.png";
                    Tower * tower=new Tower(it->getCenterPos(),this,path,20);
                    m_towerList.push_back(tower);
                }
                //构造完防御塔后,原来的button就要消失,下面对该button进行移除
                it->getButton()->getRemoved();
                it->setButton(NULL);
                it->setHasButton(false);
                update();
                break;
            }
        }
        ++it;
    }

同时在paintEvent()种添加对button的绘画:

    foreach(const selectButton * button,m_selectButtonList)
        button->draw(&painter);

运行上述代码,就可以对防御塔进行选择啦!涉及动态效果,我就不展示了。

对防御塔进行升级和移除

为了完成防御塔的升级的移除,我们同样需要构造一个button,来进行有选择地点击实现。我们命名为selectButton2类。创建文件selectButton2

selectButton2.h中的实现:

#ifndef SELECTBUTTON2_H
#define SELECTBUTTON2_H

#include <QPainter>
#include <QPoint>
#include <QRect>
#include <QSize>

#include "mainwindow.h"
#include "tower.h"

class MainWindow;
class Tower;

class selectButton2
{
public:
    selectButton2(QPoint pos,MainWindow * game);
    ~selectButton2();
    
    void draw(QPainter * painter)const;//绘画button
    void getRemoved();//移除button2
    Tower * getTower();//得到该button2地防御塔
    void setTower(Tower * tower);//设置该button2地防御塔
    bool containPos(QPoint pos);//判断点击点是否在button2的内部
    QPoint getPos();//得到button2的左上点
private:
    MainWindow * m_game;
    Tower * m_tower;
    QPoint m_pos;
    static const QSize m_fixedSize;
};
#endif // SELECTBUTTON2_H

下面将selectButton2类和其他的类进行连接

TowerPosition.h中:

//类外
#include "selectbutton2.h"

class selectButton2;
//类内
public:
    bool hasButton2();//判断该位置有没有button2
    void setHasButton2(bool hasButton2=true);//设置是否有button2
    void setButton2(selectButton2 * button);//设置button2
    selectButton2 * getButton2();//得到该位置的button2

    void setHasUpdate1(bool hasUpdate1);//设置是否有第一次升级
    bool hasUpdate1();

    void setHasUpdate2(bool hasUpdate2);//设置是否有第二次升级
    bool hasUpdate2();
    
    void setTower(Tower * tower);
    Tower * getTower();
    void setRemoveTower();//设置移除防御塔



private:
    bool m_hasButton2;
    selectButton2 * m_button2;//私有化button2
    
    bool m_hasUpdate1;
    bool m_hasUpdate2;
    
    Tower * m_tower;//私有化成员tower,为移除做准备

TowerPosition.cpp中对上面的代码进行实现:

//构造函数截取部分
    m_hasTower3(false),
    m_hasUpdate1(false),
    m_hasUpdate2(false),
    m_hasButton(false),
    m_hasButton2(false)

//其他函数
void TowerPosition::setHasButton2(bool hasButton2)
{
    m_hasButton2=hasButton2;
}

bool TowerPosition::hasButton2()
{
    return m_hasButton2;
}

void TowerPosition::setHasUpdate1(bool hasUpdate1)
{
    m_hasUpdate1=hasUpdate1;
}

bool TowerPosition::hasUpdate1()
{
    return m_hasUpdate1;
}

void TowerPosition::setHasUpdate2(bool hasUpdate2)
{
    m_hasUpdate2=hasUpdate2;
}

bool TowerPosition::hasUpdate2()
{
    return m_hasUpdate2;
}

void TowerPosition::setButton2(selectButton2 *button)
{
    m_button2=button;
}

void TowerPosition::setTower(Tower *tower)
{
    m_tower=tower;
}

Tower * TowerPosition::getTower()
{
    return m_tower;
}

selectButton2 * TowerPosition::getButton2()
{
    return m_button2;
}

void TowerPosition::setRemoveTower()
{
    setTower(NULL);
    setHasTower(false);
    setHasTower1(false);
    setHasTower2(false);
    setHasTower3(false);
    setHasUpdate1(false);
    setHasUpdate2(false);
}

mainwindow.h中进行连接:

//类外
#include "selectbutton2.h"
class selectButton2;

//类内
public:
    void removeButton2(selectButton2 * button);//在mainwindow中对button2进行移除
    void removeTower(Tower * tower);
    
    bool canUpdate1();//判断是否可以第一次升级
    bool canUpdate2();//判断是否可以第二次升级


private:
        QList<selectButton2 *> m_selectButton2List;//用来储存selectButton2的list

mainwindow.cpp中进行实现:

void MainWindow::removeTower(Tower *tower)
{
    m_towerList.removeOne(tower);
}

void MainWindow::removeButton2(selectButton2 *button)
{
    m_selectButton2List.removeOne(button);
}

bool MainWindow::canUpdate1()
{
    if(m_playerGlod>=300)
    {
        return true;
    }
    return false;
}

bool MainWindow::canUpdate2()
{
    if(m_playerGlod>=400)
    {
        return true;
    }
    return false;
}

下面我们对Tower进行改造,使其具备升级的移除的条件:
tower.h中:

//类外
#include "tower"
class Tower;

//类内
public:
    void reSetDamage(int damage);//重新设置攻击力
    int getDamgae();//得到防御塔的攻击力
    void levelChange();//防御塔升级
    int getLevel();//得到防御塔的等级

    void getRemoved();//防御塔被移除
private:
    int m_level;

tower.cpp中对其实现:

//构造函数,截取部分
    m_chooseEnemy(NULL),
    m_level(1),
    m_pos(pos),
    
//其他函数
void Tower::reSetDamage(int damage)
{
    m_damage=damage;
}

int Tower::getDamgae()
{
    return m_damage;
}

void Tower::levelChange()
{
    m_level++;
}

int Tower::getLevel()
{
    return m_level;
}

void Tower::getRemoved()
{
    if(getAttackedEnemy())//这里要判断是不是空指针NULL
    {
        getAttackedEnemy()->getLostSight(this);//移除后,敌人被该防御塔丢失视野
    }
    m_game->removeTower(this);
}

好啦,我们完成了将selectButton2与其他的类连接,现在我们实现selectButton2.cpp:

#include "selectbutton2.h"
#include "mainwindow.h"
#include <QPainter>
#include <QRect>
#include <QPoint>
#include <QString>

static const int towerupdate1Cost=300;//塔第一次升级的价钱
static const int towerupdate2Cost=400;//第二次升级

const QSize selectButton2::m_fixedSize(100,50);

selectButton2::selectButton2(QPoint pos,MainWindow * game):
    m_game(game),
    m_pos(pos)
{
}

selectButton2::~selectButton2()
{
    m_game=NULL;
    m_tower=NULL;
}

QPoint selectButton2::getPos()
{
    return m_pos;
}

void selectButton2::getRemoved()
{
    m_game->removeButton2(this);
}

void selectButton2::setTower(Tower *tower)
{
    m_tower=tower;
}

void selectButton2::draw(QPainter *painter) const
{
    int level=m_tower->getLevel();
    painter->save();
    painter->setPen(Qt::red);
    //不同等级升级的钱不一样,所以画出来也要不一样
    if(level==1)
    {//类似waves和hp的绘画
        painter->drawText(QRect(m_pos.x(),m_pos.y(),100,25),QString("update: %1").arg(towerupdate1Cost));
    }
    else
    {
        painter->drawText(QRect(m_pos.x(),m_pos.y(),100,25),QString("update: %1").arg(towerupdate2Cost));
    }
    painter->drawText(QRect(m_pos.x(),m_pos.y()+25,100,25),QString("remove"));//画出移除框
    painter->restore();
}

bool selectButton2::containPos(QPoint pos)
{
    bool xInHere=pos.x()>m_pos.x() && pos.x()<m_pos.x()+m_fixedSize.width();
    bool yInHere=pos.y()>m_pos.y() && pos.y()<m_pos.y()+m_fixedSize.height();
    return xInHere && yInHere;
}

好啦,我们再对mousePressEvent()进行添加改造,就可以实现防御塔的移除和升级了:

//先设立一个和左键点击对立的右键点击事件:
//这个else时和左键点击事件的if对立的
else if(Qt::RightButton==event->button())//如果是鼠标右键点击
        {//在有防御塔的情况下,右键会出现选择框,升级还有移除
            if(it->ContainPos(pressPos) && (!it->hasButton2()) && it->hasTower())
            {
                it->setHasButton2(true);
                QPoint tmp(it->getPos().x()+35,it->getPos().y());//我是把防御塔坑的右上顶点当作button2的端点
                selectButton2 * button2=new selectButton2(tmp,this);
                button2->setTower(it->getTower());//我写这个setTower()的目的是得到防御塔的等级,不同等级的updatecost不一样
                m_selectButton2List.push_back(button2);
                it->setButton2(button2);
                update();
                break;
            }
        }
//再添加
//下面这个else if结构添加在第二层的if中,详情可见源代码中的mousePressEvent函数
//下面的判断语句,要先判断hasbutton2,不能先判断containPos.因为如果没有button2,在进入这个判断框的时候,会先getbutton2,但是button2是NULL,程序会异常结束。
            else if(it->hasButton2() && it->getButton2()->containPos(pressPos) && !it->hasButton() && !it->ContainPos(pressPos) &&it->hasTower())
            {//在有button2的情况下,点击button2的内部
                if(pressPos.y()<(it->getButton2()->getPos().y()+25))//我直接设置了第一个选择框的height是25,这里就直接用25了
                {//对防御塔进行升级
                    if(canUpdate1() && !it->hasUpdate1() && it->hasTower())
                    {
                        it->setHasUpdate1(true);
                        m_playerGlod-=towerupdate1Cost;
                        it->getTower()->reSetDamage(it->getTower()->getDamage()+10);
                        it->getTower()->levelChange();
                    }
                    else if(canUpdate2() && it->hasUpdate1() && !it->hasUpdate2())
                    {
                        it->setHasUpdate2(true);
                        m_playerGlod-=towerupdate2Cost;
                        it->getTower()->reSetDamage(it->getTower()->getDamage()+20);
                        it->getTower()->levelChange();
                    }
                }
                else if(pressPos.y()>it->getButton2()->getPos().y()+25)
                {//对防御塔进行移除
                    awardGlod();//移除防御塔奖励200
                    it->getTower()->getRemoved();//这个移除和前面写的几个移除都是一样的
                    it->setRemoveTower();//设置移除防御塔带来的其他变化
                }
                //点击了button2的内部,button2就要被移除
                it->getButton2()->getRemoved();
                it->setButton2(NULL);
                it->setHasButton2(false);
                update();
                break;
            }

然后再到paintEvent()中,添加对button2的绘画:

    foreach(const selectButton2 * button2,m_selectButton2List)
        button2->draw(&painter);

ok,运行上述代码,我们就可以成功完成防御塔的升级和移除了。其中的主要代码分为两块,一个是button和其他类的连接,另外就是再mousePressEvent()中对他们进行鼠标上的点击实现。下面我们开始不同关卡的绘制。

实现多关卡的绘制,供玩家选择

为实现多关卡,我们要另外构造一个界面,让玩家进行选择。我们创建一个startFrom类(和创建mainwindow的方式一样)。

startFrom.h中进行实现:

#ifndef STARTFROM_H
#define STARTFROM_H

#include <QWidget>

#include "mainwindow.h"//包含mainwindow文件

namespace Ui {
class startFrom;
}
class startFrom : public QWidget
{
    Q_OBJECT
public:
    explicit startFrom(QWidget *parent = nullptr);
    ~startFrom();
    void paintEvent(QPaintEvent *event);//只用添加这个绘画类函数就可以了
private:
    Ui::startFrom *ui;
};
#endif // STARTFROM_H

好啦,现在我们需要在startFrom.ui界面添加按钮,使其可以完成和mainwindow之间的转换。
把左边的Push Button拖动到右边的界面。Qt之塔防游戏 c++ (三)
这里我们涉及了四个关卡,制作者可以根据自己的需要再制作更多的关卡,方法是一样的。由于我们新增了三个关卡,和关卡1一样,我们需要对其他的关卡进行绘制。因此再mainwindow.h中添加对其他地图的绘制:


//类外
#include <QString>

//类内
public:
    void addWayPoint2();
    void loadTowerPosition2();
    
    void loadTowerPosition3();
    void addWayPoint3();

    void loadTowerPosition4();
    void addWayPoint4();    
    
    QString getPath();//得到地图图片路径
    void setPath(QString path);//设置地图图片路径

private:
    QString m_path;

再到mainwindow.cpp中对他们进行实现:
绘制这三个地图的方法和绘制第一张地图的方法是一样的,需要制作者耐心地寻找航点和防御塔坑点。
由于篇幅关系,我就不把三个地图的具体绘制方法放出来了,就列举一个例子。如果你需要其他地图的具体绘制数据的话,在我第一篇文章中有我源代码的链接。

void MainWindow::loadTowerPosition2()
{
    QPoint pos[]=
    {
        QPoint(171,240),
        QPoint(251,240),
        QPoint(325,240),
        QPoint(270,170),
        QPoint(345,170),
        QPoint(420,170),
        QPoint(245,100),
        QPoint(520,170),
    };
    for(int i=0;i<8;i++)
    {
        m_towerPositionList.push_back(pos[i]);
    }
}

void MainWindow::addWayPoint2()
{
    wayPoint * waypoint1=new wayPoint(QPoint(177,371));
    m_wayPointList.push_back(waypoint1);

    wayPoint * waypoint2=new wayPoint(QPoint(177,292));
    waypoint1->setNextWayPoint(waypoint2);
    m_wayPointList.push_back(waypoint2);

    wayPoint * waypoint3=new wayPoint(QPoint(388,292));
    waypoint2->setNextWayPoint(waypoint3);
    m_wayPointList.push_back(waypoint3);

    wayPoint * waypoint4=new wayPoint(QPoint(388,222));
    waypoint3->setNextWayPoint(waypoint4);
    m_wayPointList.push_back(waypoint4);

    wayPoint * waypoint5=new wayPoint(QPoint(248,222));
    waypoint4->setNextWayPoint(waypoint5);
    m_wayPointList.push_back(waypoint5);

    wayPoint * waypoint6=new wayPoint(QPoint(248,151));
    waypoint5->setNextWayPoint(waypoint6);
    m_wayPointList.push_back(waypoint6);

    wayPoint * waypoint7=new wayPoint(QPoint(481,151));
    waypoint6->setNextWayPoint(waypoint7);
    m_wayPointList.push_back(waypoint7);

    wayPoint * waypoint8=new wayPoint(QPoint(481,223));
    waypoint7->setNextWayPoint(waypoint8);
    m_wayPointList.push_back(waypoint8);

    wayPoint * waypoint9=new wayPoint(QPoint(598,223));
    waypoint8->setNextWayPoint(waypoint9);
    m_wayPointList.push_back(waypoint9);

    wayPoint * waypoint10=new wayPoint(QPoint(598,149));
    waypoint9->setNextWayPoint(waypoint10);
    m_wayPointList.push_back(waypoint10);
}

void MainWindow::setPath(QString path)
{
    m_path=path;
}

QString MainWindow::getPath()
{
    return m_path;
}

再到paintEvent()中,对地图绘画进行改造:

    QString path=getPath();
    painter.drawPixmap(0,0,750,375,path);

startFrom.cpp中的功能实现:

//构造函数中的添加
    ui->setupUi(this);
    this->setFixedSize(750,375);
        setWindowTitle("start from");
        //打开第一关
        connect(ui->pushButton,&QPushButton::clicked,[=]()
        {
            MainWindow * mainwindow=new MainWindow(parent);
            mainwindow->setPath(":/images/background1.jpg");
            mainwindow->loadTowerPosition1();
            mainwindow->addWayPoint1();
            mainwindow->show();
        });
        //打开第二关
        connect(ui->pushButton_2,&QPushButton::clicked,[=]()
        {
            MainWindow * mainwindow=new MainWindow(parent);
            mainwindow->setPath(":/images/background2.jpg");
            mainwindow->loadTowerPosition2();
            mainwindow->addWayPoint2();
            mainwindow->show();
        });
        //打开第三关
        connect(ui->pushButton_3,&QPushButton::clicked,[=]()
        {
            MainWindow * mainwindow=new MainWindow(parent);
            mainwindow->setPath(":/images/background4.jpg");
            mainwindow->loadTowerPosition3();
            mainwindow->addWayPoint3();
            mainwindow->show();
        });
        //打开第四关
        connect(ui->pushButton_4,&QPushButton::clicked,[=]()
        {
            MainWindow * mainwindow=new MainWindow(parent);
            mainwindow->setPath(":/images/background5.jpg");
            mainwindow->loadTowerPosition4();
            mainwindow->addWayPoint4();
            mainwindow->show();
        });
//其他函数
void startFrom::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    QString path(":/images/background.jpg");
    painter.drawPixmap(0,0,750,375,path);
}

注意上面代码的connect的使用方法!!!

ok,现在我们到main.cpp中,修改显示界面。

//把使用mainwindow的地方,替换成startFrom
#include "startfrom.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    startFrom w;
    w.show();
    return a.exec();
}

到这里,我们就实现了多地图的绘制了。一个较为成熟的塔防游戏就诞生了!下面我们再对一些细节进行完善吧!

再有防御塔的情况下,将防御塔坑进行隐藏

我们把TowerPosition.h中的bool hasTower()函数改为 bool hasTower()const

再进入paintEvent()函数中, 将防御塔的绘画改成:

    foreach(const TowerPosition towerposition,m_towerPositionList)
    {
        if(!towerposition.hasTower())//没有防御塔,画出防御塔坑
        {
            towerposition.draw(&painter);
        }
    } 

敌人从不同路口出现的绘制
mainwindow.cpp中的loadWaves()函数改成:

bool MainWindow::loadWaves()
{
    if(m_waves>=6)
    {
        return false;
    }
    int enemyStartInterval[]={100,500,600,1000,3000,6000};
    for(int i=0;i<6;++i)
    {
        wayPoint * startWayPoint;
        if(getPath()==":/images/background4.jpg")//该地图中,敌人有多种运动方法
        {
            int a=rand()%100;//随机数
            if(a<50)
            {
                startWayPoint=m_wayPointList.first();
            }
            if(a>=50)
            {
               startWayPoint=m_wayPointList[7];
            }
        }
        else
        {
            startWayPoint=m_wayPointList.first();
        }
        Enemy * enemy=new Enemy(startWayPoint,this);
        m_enemyList.push_back(enemy);
        //enemy->reSetHp(40+35*(0+m_waves));//波数增加,怪物的血量增加,一次加30点,这里可以进行重新设置敌人血量的操作
        //还可以增加修改速度的函数
        QTimer::singleShot(enemyStartInterval[i],enemy,SLOT(doActive()));
    }
    return true;
}

出了以上我说到了两种完善,制作者还有很大的发挥空间。比如升级后,防御塔的体型变大,攻击速度等;或者是敌人随着波数的增加,移动速度加快等等。总之还有很大的发挥空间,但是其基本方法和我上面的方法是一样的,都是一个reSet的过程。

这是我平生第一次写游戏,以前想都不敢想的事情,在自己的慢慢摸索下实现了,还挺有成就感的。虽然过程挺艰难的,在无数次debug中想要放弃,但还是尽力坚持下来了。这三篇文章也许还有很多不足的地方,若有谬误,也还请各位海涵,我也希望你们私信我,指出我不足的地方,慢慢提高吧!

编程真的是一件痛并快乐着的事情,希望各位代码小伙伴们在编程中都找到属于自己的快乐和幸福吧!

最后再附上源代码的链接:
https://pan.baidu.com/s/1BS7tiiyCWQxgZDsm8QhMgA
提取码:9307

完结撒花!

上一篇:基于QT实现简单的音乐播放器


下一篇:mysql--以C#打开数据库并且查询和显示数据