话不多说,我们直接进入正题吧。
这个阶段我们要完成如下功能:
1:图片的绘制
2:敌人运动轨迹的绘制
3:防御塔坑(可放置防御塔点)的绘制
4:鼠标点击事件,实现防御塔的出现
图片的绘制
首先我们在Qt中,创建一个widget工程
得到这个工程后,我们在mainwindow.h中做如下添加:
//类外
#include <QPaintEvent>
//类内
protected:
void paintEvent(QPaintEvent*);
添加Qt Resource File文件
把要用到的图片都放到这个文件夹中。
然后进入mainwindow.cpp,做如下添加:
void Mainwindow::paintEvent(QPaintEvent*)
{
QPainter painter(this);
QString path(":/images/background1.jpg");//path是你图片的路径
painter.drawPixmap(0,0,750,375,path);
//drawPixmap的前四个参数代表的分别是,图片左上角的横坐标,图片左上角的纵坐标,图片的width,图片的height。我们一般把width和height,与图片的真实大小匹配起来
}
运行上述程序,就可以得到下面的结果啦!
#敌人运动轨迹的绘制
我们添加一个类wayPoint(航点)
在wayPoint.h的实现:
#ifndef WAYPOINT_H
#define WAYPOINT_H
#include <QPoint>
#include <QPainter>
class wayPoint
{
public:
wayPoint(QPoint pos);
void setNextWayPoint(wayPoint * nextWayPoint);//设置下一个航点
wayPoint * getNextWayPoint();//得到下一个航点的指针
const QPoint getPos();//得到本航点的中心点
void draw(QPainter * painter) const;//绘画类函数
private:
QPoint m_pos;//航点的中心点
wayPoint * m_nextWayPoint;//下一个航点的指针
};
#endif // WAYPOINT_H
wayPoint.cpp中的实现:
#include "waypoint.h"
#include <QPoint>
#include <QPainter>
wayPoint::wayPoint(QPoint pos):
m_pos(pos),
m_nextWayPoint(NULL)
{
}
void wayPoint::setNextWayPoint(wayPoint *nextWayPoint)
{
this->m_nextWayPoint=nextWayPoint;
}
wayPoint * wayPoint::getNextWayPoint()
{
return this->m_nextWayPoint;
}
const QPoint wayPoint::getPos()
{
return this->m_pos;
}
void wayPoint::draw(QPainter * painter) const
{
painter->save();//保存原始的绘画参数
painter->setPen(Qt::green);//设置画笔的颜色
painter->drawEllipse(m_pos,4,4);//画一个半径为4的圆
//注意,图片的大小单位是像素
painter->drawEllipse(m_pos,1,1);//半径为1的圆
if(m_nextWayPoint)//如果存在下一个航点,就把这两个航点连接起来
{
painter->drawLine(m_pos,m_nextWayPoint->getPos());//painter内的画直线的方法
}
painter->restore();//还原原来的画笔设置
}
完成wayPoint类的创建后,我们在mainwindow(程序运行得到的窗口)中把这些航点画出来。
先在mainwindow.h中添加:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPaintEvent>
#include "waypoint.h"//我们一般引用系统内文件时,用<>,引用我们自己定义的文件时用""
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class wayPoint;//新增对wayPoint类的说明
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void addWayPoint1();//用来添加航点的函数
protected:
void paintEvent(QPaintEvent*);//画家类函数
private:
Ui::MainWindow *ui;
QList<wayPoint * > m_wayPointList;//用来储存航点的list
};
#endif // MAINWINDOW_H
mainwindow.cpp中的实现:
//增加头文件的引用
#include "waypoint.h"
//函数的实现
void MainWindow::addWayPoint1()
{
wayPoint * waypoint1=new wayPoint(QPoint(79,6));
m_wayPointList.push_back(waypoint1);
wayPoint * waypoint2=new wayPoint(QPoint(79,55));
waypoint1->setNextWayPoint(waypoint2);
m_wayPointList.push_back(waypoint2);
wayPoint * waypoint3=new wayPoint(QPoint(407,55));
waypoint2->setNextWayPoint(waypoint3);
m_wayPointList.push_back(waypoint3);
wayPoint * waypoint4=new wayPoint(QPoint(407,175));
waypoint3->setNextWayPoint(waypoint4);
m_wayPointList.push_back(waypoint4);
wayPoint * waypoint5=new wayPoint(QPoint(83,175));
waypoint4->setNextWayPoint(waypoint5);
m_wayPointList.push_back(waypoint5);
wayPoint * waypoint6=new wayPoint(QPoint(83,292));
waypoint5->setNextWayPoint(waypoint6);
m_wayPointList.push_back(waypoint6);
wayPoint * waypoint7=new wayPoint(QPoint(473,292));
waypoint6->setNextWayPoint(waypoint7);
m_wayPointList.push_back(waypoint7);
}
航点的绘制要比较有耐心
游戏世界的构造是以左上角为原点的,以像素为单位
制作者需要自己不断修改,在图上找到这些航点,调整,找到航点的确切位置
下面的具体数据,是适用于我使用的地图的
如果制作者要用其他的背景地图,需要自己修改数据,找到航点
我们再到mainwindow.cpp的paintEvent()方法中添加航点的绘画的实现:
foreach(const wayPoint * waypoint,m_wayPointList)
waypoint->draw(&painter);
再到mainwindow.cpp中mainwindow的构造函数中,添加addWayPoint1()的调用:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
addWayPoint1();//增加航点函数的调用
}
运行程序,我们就可以得到下面的结果啦!
可以看到,图上已经有敌人运动的轨迹了。
好啦,接下来我们进行防御塔坑的绘制。
防御塔坑的绘制
先添加 TowerPosition 类
在 TowerPosition.h中的实现:
#ifndef TOWERPOSITION_H
#define TOWERPOSITION_H
#include <QSize>
#include <QPainter>
#include <QString>
class TowerPosition
{
public:
TowerPosition(QPoint pos,QString path=(":/images/open_spot.png"));//图片的路径
QPoint getCenterPos();//得到防御塔坑的中心点
QPoint getPos();//得到防御塔坑的左上点
bool ContainPos(QPoint pos);//判断pos点是否在防御塔坑的范围内
void draw(QPainter * painter) const;
bool hasTower();//判断该防御塔坑内有没有防御塔
void setHasTower(bool hasTower=true);//设置是否有防御塔
private:
QPoint m_pos;
QString m_path;
bool m_hasTower;
static const QSize m_fixedSize;//防御塔坑的固定大小
};
#endif // TOWERPOSITION_H
TowerPosition.cpp的实现:
#include "towerposition.h"
#include <QSize>
#include <QPainter>
#include <QPixmap>
const QSize TowerPosition::m_fixedSize(35,35);//设置图片的大小
TowerPosition::TowerPosition(QPoint pos, QString path):
m_pos(pos),
m_path(path),
m_hasTower(false)
{
}
bool TowerPosition::hasTower()
{
return m_hasTower;
}
void TowerPosition::setHasTower(bool hasTower)
{
m_hasTower=hasTower;
}
QPoint TowerPosition::getCenterPos()
{
QPoint tmp;
tmp.setX(m_pos.x()+m_fixedSize.width()/2);
tmp.setY(m_pos.y()+m_fixedSize.height()/2);
return tmp;
}
QPoint TowerPosition::getPos()
{
return m_pos;
}
bool TowerPosition::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;
}
void TowerPosition::draw(QPainter *painter) const
{
painter->drawPixmap(m_pos.x(),m_pos.y(),m_path);
}
然后到mainwindow.h中添加下面代码
//类外
#include <towerposition.h>
//类内
public:
void loadTowerPosition1();//用来加载防御塔坑的函数
private:
QList<TowerPosition > m_towerPositionList;//用来储存防御塔坑的list
在mainwindow.cpp中对上面的代码进行实现:
#include"towerposition"
void MainWindow::loadTowerPosition1()
{
//这里和找航点是一样的,制作者需要自己不断尝试
//找到比较合适的防御塔坑点
QPoint pos[]=
{
QPoint(86,98),
QPoint(226,98),
QPoint(439,98),
QPoint(105,215),
QPoint(186,215),
QPoint(314,215),
QPoint(105,321),
QPoint(223,323),
QPoint(365,319)
};
int len=sizeof(pos)/sizeof(pos[0]);
for(int i=0;i<len;i++)
{
m_towerPositionList.push_back(pos[i]);
}
}
同时,在paintEvent()函数内添加对防御塔坑的绘画:
foreach(const TowerPosition towerposition,m_towerPositionList)
towerposition.draw(&painter);
并在mainwindow的构造函数中,添加对loadTowerPosition1()方法的调用,类似addWayPoint1()的调用:
loadTowerPosition1();
运行上述程序,我们可以得到下面的界面:
可以看到,我们已经画出来了敌人的航点和防御塔坑
下面就实现防御塔的安置吧!
鼠标点击实现防御塔的出现
我们先创建一个 Tower 类
tower.h中的实现:
#ifndef TOWER_H
#define TOWER_H
#include <QObject>
#include <QPoint>
#include <QSize>
#include <QString>
#include "mainwindow.h"
class MainWindow;
class QPainter;
class Tower:QObject
{
Q_OBJECT
public:
Tower(QPoint pos,MainWindow * game,QString path=":/images/tower2.png");
~Tower();
Tower();
void draw(QPainter * painter)const;//画出防御塔
private:
QPoint m_pos;//防御塔的中心点
QString m_path;//防御塔图片的路径
int m_attackRange;//攻击范围
static const QSize m_fixedSize;//防御塔图片的固定大小
MainWindow * m_game;//指向mainwindow的指针
};
#endif // TOWER_H
同时,tower.cpp中的方法实现:
#include "tower.h"
#include "mainwindow.h"
#include <QPoint>
#include <QPainter>
#include <QString>
const QSize Tower::m_fixedSize(35,35);
Tower::Tower()
{
}
Tower::~Tower()
{
}
Tower::Tower(QPoint pos,MainWindow * game,QString path):
m_pos(pos),
m_path(path),
m_attackRange(70),//根据地图的大小,确定攻击范围
m_game(game)
{
}
void Tower::draw(QPainter *painter) const
{
painter->save();
painter->setPen(Qt::green);
painter->drawEllipse(m_pos,m_attackRange,m_attackRange);//画出防御塔的攻击范围
painter->drawPixmap(m_pos.x()-m_fixedSize.width()/2,m_pos.y()-m_fixedSize.height()/2-10,path);//画出防御塔的图片
}
在mainwindow.h中做如下添加:
//类外添加
#include <QMouseEvent>
#include "tower.h"
class Tower;
//类内添加
protected:
void mousePressEvent(QMouseEvent *);//鼠标点击类函数
private:
QList<Tower *> m_towerList;//用来储存防御塔的list
在mainwindow.cpp中,对mousePressEvent()进行实现:
void MainWindow::mousePressEvent(QMouseEvent * event)
{
QPoint pressPos=event->pos();//得到鼠标点击的位置
auto it=m_towerPositionList.begin();
while(it!=m_towerPositionList.end())//遍历所有的防御塔坑
{
if(Qt::LeftButton==event->button())//如果是鼠标左键点击
{
if(it->ContainPos(pressPos) && !it->hasTower())//如果鼠标点击的位置在防御塔坑的范围内,并且没有防御塔
{
Tower * tower=new Tower(it->getCenterPos(),this);//创建一个新的防御塔
m_towerList.push_back(tower);//把这个防御塔放到储存防御塔的list中
it->setHasTower(true);//设置这个防御塔坑内有防御塔了
update();//更新地图
break;//进行了一次操作,可以直接退出循环了
}
}
++it;
}
}
并在paintEvent()函数中,添加对防御塔的绘画:
foreach(const Tower * tower, m_towerList)
tower->draw(&painter);
运行程序后,我们就可以得到下面的画面了:
可以看到,点击防御塔坑的内部后,防御塔就会出现。
这样我们第一阶段的工作就完成啦!
下面我们对这次的工作进行一次总结:
1:首先我们完成了背景地图的绘画,用到了QPainter头文件中的drawPixmap()函数,后续的一些绘画也多次用到了这个函数。
2:我们画出了敌人运动的航点,这个过程比较麻烦,需要制作者根据mainwindow上的实际情况,不断调整航点的位置
3:引入防御塔坑,为防御塔的出现做铺垫,我们后续的很多操作,主要是鼠标点击事件,都将会以TowerPosition为基础进行操作。
4:实现鼠标点击事件,完成防御塔的出现。
OK,我们下一篇文章见!
所有的源代码和图片资源,在下面的网盘内:
https://pan.baidu.com/s/1BS7tiiyCWQxgZDsm8QhMgA
提取码:9307