在基本功能实现后,对游戏进行优化,主要有以下几部分
- 实现传奇的升级
- 实现传奇的移除
- 绘画出波数与血量
- 实现游戏的暂停与回到选关关卡
- 实现游戏的胜利与失败
1.实现传奇的升级
创建一个selectbutton2类
#ifndef SELECTBUTTON2_H
#define SELECTBUTTON2_H
#include <QPainter>
#include <QPoint>
#include <QSize>
#include"gamescene.h"
#include"legends.h"
class Gamescene;
class Legends;
class SelectButton2
{
public:
SelectButton2();
SelectButton2(QPoint pos,Gamescene *game,QString path);
virtual ~SelectButton2();
//绘画button
void virtual draw(QPainter * painter)const;
//移除button2
void virtual getRemoved();
//得到该button2的传奇
Legends * getLegend();
//设置该button2的传奇
void setLegend(Legends * legend);
//判断点击点是否在button2的内部
bool containPos(QPoint pos);
//得到button2的左上点
QPoint getPos();
//图片固定大小
static const QSize myfixedSize;
protected:
//指向游戏界面的指针
Gamescene *mygame;
//我的传奇
Legends *mylegend;
//坐标点
QPoint mypos;
//图片地址
QString mypath;
};
#endif // SELECTBUTTON2_H
与gamescene连接.h中加入
//移除button1
void removeButton(SelectButton *button);
//可以购买
bool canBuy();
bool canBuy2();
bool canBuy3();
//selectbutton1列表
QList<SelectButton*> myselectButtonList;
.cpp中加入
//画出button
foreach (const SelectButton*button ,myselectButtonList)
{
button->draw(&painter);
}
//判断可以升级
bool Gamescene::canUpdate(int money)
{
if(myMoney>=money)
{
return true;
}
return false;
}
//移除button1
void Gamescene::removeButton(SelectButton *button)
{
Q_ASSERT(button);
myselectButtonList.removeOne(button);
}
与legends连接
.h中加入
//传奇升级
void levelUp();
//得到传奇等级
int getLevel();
//得到传奇的攻击力
int getDamage();
//传奇升级的价格
int myupdate1Money;
.cpp中加入
//重置伤害
void Legends::reSetDamage()
{
Legend[mynum].mydamage*=2;
}
//得到重置后的伤害
//设置升级
void Legends::levelUp()
{
mylevel++;
}
//得到等级
int Legends::getLevel()
{
return mylevel;
}
//得到升级的金钱
int Legends:: getUpdate1Money()
{
myupdate1Money=Legend[mynum].mymoney*2-100;
std::cout<<myupdate1Money<<std::endl;
return myupdate1Money;
}
连接完成后在selectbutton2.cpp中实现
#include "selectbutton2.h"
const QSize SelectButton2::myfixedSize(90,90);
//构造函数
SelectButton2::SelectButton2(QPoint pos,Gamescene *game,QString path):
mygame(game),
mypos(pos),
mypath(path)
{
}
//析构函数
SelectButton2::~SelectButton2()
{
mygame=NULL;
mylegend=NULL;
}
//得到坐标
QPoint SelectButton2::getPos()
{
return mypos;
}
//移除该button
void SelectButton2::getRemoved()
{
mygame->removeButton2(this);
mygame->removeButton3(this);
}
//设置此处的传奇
void SelectButton2::setLegend(Legends *Legend)
{
mylegend=Legend;
}
//绘画函数
void SelectButton2::draw(QPainter *painter) const
{
painter->save();
painter->drawPixmap(mypos.x(),mypos.y(),myfixedSize.width(),myfixedSize.height(),mypath);
painter->restore();
}
//存在选择框
bool SelectButton2::containPos(QPoint pos)
{
bool xInHere=(pos.x()>mypos.x() && pos.x()<mypos.x()+myfixedSize.width());
bool yInHere=(pos.y()>mypos.y() && pos.y()<mypos.y()+myfixedSize.height());
return xInHere && yInHere;
}
最后在gamescene中改写鼠标事件函数即可,与下一步移除同时进行
2.实现传奇的移除
sellectbutton2已经全部展现,将其与gamescene连接
.h
//selectButton3列表
QList<SelectButton2 *> myselectButton3List;
//移除传奇
void removeLegend(Legends*legend);
//移除button3
void removeButton3(SelectButton2 *button3);
///.cpp
//移除button3
void Gamescene::removeButton3(SelectButton2 *button3)
{
Q_ASSERT(button3);
myselectButton3List.removeOne(button3);
}
//移除传奇
void Gamescene::removeLegend(Legends *legend)
{
Q_ASSERT(legend);
mylegendlist.removeOne(legend);
}
与legends连接
//.h
//移除传奇
void getRemoved();
//.cpp
//移除传奇
void Legends::getRemoved()
{
//这里要判断是不是空指针NULL,防止子弹错误
if(getAttackedEnemy()!=NULL)
{
//移除后,敌人被该防御塔丢失视野
getAttackedEnemy()->getLostSight(this);
}
mygame->removeLegend(this);
}
最后将1,2两部结合,改写gamescene函数
//鼠标事件,点击生成传奇
void Gamescene::mousePressEvent(QMouseEvent *event)
{
//获取点击的坐标
QPoint presspos=event->pos();
//如果点击暂停
if(hasPresspos(presspos,QPoint(1560,0),QSize(90,90))&&Qt::LeftButton==event->button())
{ if(flag1/2==0)
{
flag1++;
pause();
cout<<flag1<<endl;
}
else {
timer->start(30);
flag1--;
}
}
//如果点击菜单
if(hasPresspos(presspos,QPoint(1710,0),QSize(100,100))&&Qt::LeftButton==event->button())
{ if(flag2/2==0)
{
flag2++;
pause();
}
}
if(hasPresspos(presspos,QPoint(1690,120),QSize(175,60))&&Qt::LeftButton==event->button()&&flag2/2!=0)
{
timer->start(30);
flag2--;
}
else if(hasPresspos(presspos,QPoint(1690,185),QSize(175,60))&&Qt::LeftButton==event->button())
{
choose *a=new choose;
this->hide();
a->show();
}
//创建传奇列表
auto legend_locationList=mylegend_loclist.begin();
// 遍历所有传奇格子
while(legend_locationList!=mylegend_loclist.end())//遍历所有的防御塔坑
{
//如果是鼠标左键点击,可以实现传奇的建立,或者是在有button2时进行升级或者移除
if(Qt::LeftButton==event->button())
{
//如果没有button,点击的点在防御塔坑的内部
if(legend_locationList->containPos(presspos) &&!legend_locationList->hasButton() && !legend_locationList->hasLegend()&&!legend_locationList->hasButton2())
{
//得到该防御塔坑处的button的左上点
QPoint tmp(legend_locationList->getPos().x(),legend_locationList->getPos().y());
//创建一个button
SelectButton * button=new SelectButton(tmp,this);
//设置该位置有button
legend_locationList->setHasButton(true);
//设置该位置的button
legend_locationList->setButton(button);
//把这个button加入到gamescene中
myselectButtonList.push_back(button);
update();
break;
}
//判断是否有button2/3,没有button1,点击点不在传奇内,存在传奇
else if(legend_locationList->hasButton2() && !legend_locationList->hasButton() && !legend_locationList->containPos(presspos) &&legend_locationList->hasLegend())
{
//在有button2的情况下,点击button2的内部
if(hasPresspos(presspos,legend_locationList->getButton2()->getPos(),legend_locationList->getButton2()->myfixedSize))
{
//对防御塔进行升级
//金币足以升级,传奇没有升级过,该位置有传奇
if(canUpdate(legend_locationList->getLegends()->getUpdate1Money()) && !legend_locationList->hasUpdate1() && legend_locationList->hasLegend())
{
//设置已经升级
legend_locationList->setHasUpdate1(true);
//扣除金币
myMoney-=legend_locationList->getLegends()->getUpdate1Money();
//重置伤害
legend_locationList->getLegends()->reSetDamage();
//记录传奇升级
legend_locationList->getLegends()->levelUp();
}
}
//点击点在button3内,对防御塔进行移除
else if(hasPresspos(presspos,legend_locationList->getButton3()->getPos(),legend_locationList->getButton3()->myfixedSize))
{
//移除防御塔奖励200
awardMoney();
//这个移除传奇
legend_locationList->getLegends()->getRemoved();
//设置移除防御塔带来的其他变化
legend_locationList->setRemoveLegend();
}
//点击了button2/3的内部,button2/3就要被移除
legend_locationList->getButton2()->getRemoved();
legend_locationList->setButton2(NULL);
legend_locationList->setHasButton2(false);
legend_locationList->getButton3()->getRemoved();
legend_locationList->setButton3(NULL);
legend_locationList->setHasButton3(false);
update();
break;
}
//如果这个位置有button,没有防御塔,开始创建传奇
else if(legend_locationList->hasButton() && !legend_locationList->hasLegend())
{
//如果鼠标点击的地方在第一张图片内,创造第一个传奇
if(presspos.x()<legend_locationList->getButton()->getPos().x()+120 && canBuy())
{
legend_locationList->setHasLegend1(true);
Legends * legend=new Legends(legend_locationList->getCenterPos(),this,1);
myMoney-=legend->getMoney();
legend_locationList->setLegend(legend);
mylegendlist.push_back(legend);
}
//鼠标点击点在第二张图片内,创建第二种传奇
else if(presspos.x()>legend_locationList->getButton()->getPos().x()+125
&& presspos.x()<legend_locationList->getButton()->getPos().x()+245
&& canBuy2())
{
legend_locationList->setHasLegend2(true);
Legends * legend=new Legends(legend_locationList->getCenterPos(),this,2);
myMoney-=legend->getMoney();
legend_locationList->setLegend(legend);
mylegendlist.push_back(legend);
}
//鼠标点击点在第二张图片内,创建第三种传奇
else if(presspos.x()>legend_locationList->getButton()->getPos().x()+250 && presspos.x()<legend_locationList->getButton()->getPos().x()+375
&& canBuy3())
{
legend_locationList->setHasLegend3(true);
Legends * legend=new Legends(legend_locationList->getCenterPos(),this,3);
myMoney-=legend->getMoney();
legend_locationList->setLegend(legend);
mylegendlist.push_back(legend);
}
//构造完防御塔后,对该button进行移除
legend_locationList->getButton()->getRemoved();
legend_locationList->setButton(NULL);
legend_locationList->setHasButton(false);
update();
break;
}
}
//如果是鼠标右键点击
else if(Qt::RightButton==event->button())
{
//在有防御塔的情况下,右键会出现选择框,升级还有移除
if(legend_locationList->containPos(presspos) && (!legend_locationList->hasButton2()) && legend_locationList->hasLegend())
{
legend_locationList->setHasButton2(true);
legend_locationList->setHasButton3(true);
//创建button2
QPoint tmp1(legend_locationList->getPos().x()+10,legend_locationList->getPos().y()-90);
SelectButton2 * button2=new SelectButton2(tmp1,this,":/image/LevelUp.png");
myselectButton2List.push_back(button2);
legend_locationList->setButton2(button2);
//创建button2
QPoint tmp2(legend_locationList->getPos().x()+15,legend_locationList->getPos().y()+130);
SelectButton2 * button3=new SelectButton2(tmp2,this,":/image/remove.png");
myselectButton3List.push_back(button3);
legend_locationList->setButton3(button3);
button2->setLegend(legend_locationList->getLegends());
update();
break;
}
}
++ legend_locationList;
}
}
对了,gamescene中增加了判断点击点的函数
//判断点击点是否在图片内
bool Gamescene:: hasPresspos(QPoint pos_a,QPoint pos_b,const QSize size_c)
{
int xx=pos_a.x()-pos_b.x();
int yy=pos_a.y()-pos_b.y();
if(xx>0&&xx<size_c.width()&&yy>0&&yy<size_c.height())
{
return true;
}
return false;
}
以上便是实现传奇升级和移除的函数
3.绘画出波数,金钱与血量
为了便于QT绘画,要将int变成string
创建一个递归函数
/递归函数获取字符串便于打印
QString Gamescene:: getMoneyPath(QString path,int money)
{
if(money/10!=0)
{
path+='0'+(money%10);
return getMoneyPath(path,money/10);
}
return (path+='0'+money);
}
在paintevent函数中实现,用了reverse函数调转方向
//画出金钱数量
QColor color (255,255,255);
QFont font1("宋体",45,QFont::Bold);
painter.setPen(color);
painter.setFont(font1);
QString moneyPath;
moneyPath=getMoneyPath(moneyPath,myMoney);
reverse(moneyPath.begin(),moneyPath.end());
painter.drawText(180,82,moneyPath);
//画出波数
QString wavePath="0";
wavePath+='0'+myWave+1;
wavePath+="/06波怪物";
painter.drawText(730,82,wavePath);
//画出生命
QFont font2("宋体",20,QFont::Bold);
painter.setFont(font2);
QString lifePath;
lifePath=getMoneyPath(lifePath,myHomeHp);
reverse(lifePath.begin(),lifePath.end());
painter.drawText(1800,355,lifePath);
实现以上效果
4.实现暂停与返回菜单
创建游戏终止函数
// 游戏暂停
void Gamescene:: pause()
{
updateMap();
timer->stop();
}
利用flag实现暂停与继续,在鼠标事件函数实现
//如果点击暂停
if(hasPresspos(presspos,QPoint(1560,0),QSize(90,90))&&Qt::LeftButton==event->button())
{ if(flag1/2==0)
{
flag1++;
pause();
cout<<flag1<<endl;
}
else {
timer->start(30);
flag1--;
}
}
//如果点击菜单
if(hasPresspos(presspos,QPoint(1710,0),QSize(100,100))&&Qt::LeftButton==event->button())
{ if(flag2/2==0)
{
flag2++;
pause();
}
}
if(hasPresspos(presspos,QPoint(1690,120),QSize(175,60))&&Qt::LeftButton==event->button()&&flag2/2!=0)
{
timer->start(30);
flag2--;
}
else if(hasPresspos(presspos,QPoint(1690,185),QSize(175,60))&&Qt::LeftButton==event->button())
{
choose *a=new choose;
this->hide();
a->show();
}
绘画函数中实现可视化
//画出暂停
QString pausePath=":/image/pause.jpg";
if(flag1==1)
painter.drawPixmap(1550,0,100,100,pausePath);
//画出菜单
QString list1Path=":/image/LIST1.jpg";
QString list2Path=":/image/LIST2.jpg";
if(flag2==2)
{
painter.drawPixmap(1690,120,175,60,list1Path);
painter.drawPixmap(1690,185,175,60,list2Path);
}
动态效果不再展示
5.实现游戏的胜利与失败
创建settlement与settlement2类分别表现进行与失败
///.h
#ifndef SETTLEMENT_H
#define SETTLEMENT_H
#include <QWidget>
#include"gamescene.h"
#include"choose.h"
class Gamescene;
class choose;
class Settlement : public QWidget
{
Q_OBJECT
public:
explicit Settlement(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) ;
void mousePressEvent(QMouseEvent *event) ;
signals:
};
#endif // SETTLEMENT_H
.cpp
#include "settlement.h"
Settlement::Settlement(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("APEX");
// 设置窗口大小
this->setFixedSize(1920,1080);
// 设置图标
this->setWindowIcon(QIcon("://cal.ico.png"));
}
void Settlement::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QString path=":/image/win.jpg";
painter.drawPixmap(0,0,1920,1080,path);
}
void Settlement::mousePressEvent(QMouseEvent *event)
{
if(Qt::LeftButton==event->button())
{
choose *a=new choose;
this->hide();
a->show();
}
}
///.h
#ifndef SETTLEMENT2_H
#define SETTLEMENT2_H
#include <QWidget>
#include"gamescene.h"
#include"choose.h"
class Gamescene;
class choose;
class Settlement2 : public QWidget
{
Q_OBJECT
public:
explicit Settlement2(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) ;
void mousePressEvent(QMouseEvent *event) ;
signals:
};
#endif // SETTLEMENT2_H
///.cpp
#include "settlement2.h"
Settlement2::Settlement2(QWidget *parent) : QWidget(parent)
{
this->setWindowTitle("APEX");
// 设置窗口大小
this->setFixedSize(1920,1080);
// 设置图标
this->setWindowIcon(QIcon("://cal.ico.png"));
}
void Settlement2::paintEvent(QPaintEvent *)
{
QPainter painter(this);
QString path=":/image/lose.jpg";
painter.drawPixmap(0,0,1920,1080,path);
}
void Settlement2::mousePressEvent(QMouseEvent *event)
{
if(Qt::LeftButton==event->button())
{
choose *a=new choose;
this->hide();
a->show();
}
}
在gamescene中实现
void Gamescene::getHpDamaged()
{
//敌人进入基地,扣一滴血
myHomeHp-=1;
//如果血量空了,游戏失败
if(myHomeHp<=0)
{
timer->stop();
Settlement2 *b=new Settlement2;
b->show();
this->hide();
}
}
分别实现了失败与成功的结算界面
总结:游戏功能基本实现,总结一下遇到的问题
1.鼠标点击函数之间的逻辑矛盾,导致最开始功能无法实现
2.多线程问题,在关闭程序之前没有结束updatemap,导致出现很多次失败界面