Qt版本-塔防游戏实现一_qt4 魔塔-程序员宅基地

技术标签: C++  Qt  塔防  游戏  

这个游戏来源于一篇较早的国外作品,不过原作是以Cocos2D为基础实现的,链接见下:

http://www.raywenderlich.com/37701/how-to-make-a-tower-defense-game-tutorial

这里呢,采用Qt5.1的库,进行移植了,这里就直接如主题了:


先看下游戏运行效果:



这里的图片,感谢原作者无私的资源,嘿嘿,借来用用

背景地图大小是480*320,这也是游戏界面的固定大小,setFixedSize(480, 320)

好了,看完效果,一步步走吧!


这是我的编译环境,去下最新版本的Qt就可以了,Qt4.x的不保证可以跑起来,没测过啦~,\(^o^)/~



1、绘制游戏背景,加载炮塔安放位置

创建一个工程,窗口采用QMainWindow或QWidget都可以,这里就用QWidget了,配上ui文件


设置好固定大小,就可以和ui文件说拜拜了,接下来基本上就都是绘制了


添加图片资源文件,这里的源代码在文章结束后会放出链接的,资源文件都在那了,友情设置0分,欢迎下载,给我长点分呗,hohoho~


然后就先画上背景图片呗~

重载MainWindow(就是QWidget)中的paintEvent函数:

void MainWindow::paintEvent(QPaintEvent *)
{
	QPainter painter(this);
	painter.drawPixmap(0, 0, QPixmap(":/image/Bg.png"));
}

这里就可以显示背景图片,效果图就不先放了

再来需要加载可以安放塔的位置,这个,原作者采用读取xml文件的,这里做测试,就直接先用数组替换了,那个xml文件的数值似乎有问题,因此这里我查找了下点,这里是我找的测试安放坐标点(这样貌似缺少弹性,以后再改为xml读取嘛,笑~)


关于TowerPosition应该有的信息见下:



这里,明显m_pos就是安放塔位置进行绘制的坐标点(左上角)

m_hasTower,用于表明该位置是否有塔

m_sprite则是保存绘制图片

需要的主要就是绘制方法,已经获得将来判断点击的点是否包含在该区域内,以决定是否可以安放塔

先查看下声明吧!

class TowerPosition
{
public:
	TowerPosition(QPoint pos, const QPixmap &sprite = QPixmap(":/image/open_spot.png"));

	void setHasTower(bool hasTower = true);
	bool hasTower() const;
	const QPoint centerPos() const;
	bool containPoint(const QPoint &pos) const;

	void draw(QPainter *painter) const;

private:
	QPoint		m_pos;
	bool		m_hasTower;
	QPixmap		m_sprite;

	static const QSize ms_fixedSize;
};
这里很简单,相应的实现也非常的直白,见下:

const QSize TowerPosition::ms_fixedSize(44, 44);

TowerPosition::TowerPosition(QPoint pos, const QPixmap &sprite/* = QPixmap(":/image/open_spot.png")*/)
	: m_pos(pos)
	, m_hasTower(false)
	, m_sprite(sprite)
{
}

const QPoint TowerPosition::centerPos() const
{
	QPoint offsetPoint(ms_fixedSize.width() / 2, ms_fixedSize.height() / 2);
	return m_pos + offsetPoint;
}

bool TowerPosition::containPoint(const QPoint &pos) const
{
	bool isXInHere = m_pos.x() < pos.x() && pos.x() < (m_pos.x() + ms_fixedSize.width());
	bool isYInHere = m_pos.y() < pos.y() && pos.y() < (m_pos.y() + ms_fixedSize.height());
	return isXInHere && isYInHere;
}

bool TowerPosition::hasTower() const
{
	return m_hasTower;
}

void TowerPosition::setHasTower(bool hasTower/* = true*/)
{
	m_hasTower = hasTower;
}

void TowerPosition::draw(QPainter *painter) const
{
	painter->drawPixmap(m_pos.x(), m_pos.y(), m_sprite);
}
之后所有对象信息,几乎都会包含这3个,坐标点,尺寸大小,图片信息,管理也都集中放在容器交给MainWindow管理


在MainWindow的private区域添加

QList<TowerPosition> m_towerPositionsList;

同时添加私有方法loadTowerPosition用于从XML文件中读取塔安放位置的信息(m_pos),不过目前从简

查看下实现:

void MainWindow::loadTowerPositions()
{
	QPoint pos[] =
	{
		QPoint(65, 220),
		QPoint(155, 220),
		QPoint(245, 220),
		QPoint(335, 220),

		QPoint(100, 125),
		QPoint(195, 125),
		QPoint(280, 125),
		QPoint(370, 125),

		QPoint(80, 35),
		QPoint(170, 35),
		QPoint(260, 35),
		QPoint(350, 35)
	};
	int len	= sizeof(pos) / sizeof(pos[0]);

	for (int i = 0; i < len; ++i)
		m_towerPositionsList.push_back(pos[i]);
}
这里没有new,是因为TowerPosition结构简单,而且本身也只会被初始化一次,因此就这样愉快决定简单处理啦,哦也

然后再paintEvent中补上绘制就Ok了!


对了,还需要在MainWindow的构造中调用loadTowerPosition才可以,可以看下效果图啦~



终于完成第一步了,起码游戏界面现在看起来是那么回事了,想来应该是要添加一些家园卫士了,攻击塔搞起


2、攻击塔的初步实现

这里只是一个简单,简单,非常简单,不带减速的小小攻击塔,可以自由添加发挥~\(≧▽≦)/~啦啦啦

同样,先看下攻击塔有哪些必要属性:



首先有必备的3件套,坐标点,尺寸大小(这个是静态常量,其实就是图片的大小),图片

额外的属性,根据名字也很好猜测

m_attackRange,攻击范围,就是以塔的中心为原点,绘制一个圆,这个的半径就是攻击范围,默认为70

m_damage,塔的伤害值,后期用到,对敌人造成的费血,原作者看来相当不残忍,攻击力居然只有10点,好吧,我数值平衡很差啦~

m_fireRate,攻击平率,这里是用毫秒记,默认是1000ms,也就是1秒攻击1次


需要添加的方法,目前只有draw方法:

draw中干2件事,先绘制一个白色的圆,这是攻击范围(主要是方便测试观察),再绘制塔

这里的m_pos则表示塔的圆心

painter->save();
painter->setPen(Qt::white);
// 绘制攻击范围
painter->drawEllipse(m_pos, m_attackRange, m_attackRange);

// 绘制偏转坐标,由中心+偏移=左上
// 尺寸大小派上用场了,当然也可以直接获取图片大小,是一样的
static const QPoint offsetPoint(-ms_fixedSize.width() / 2, -ms_fixedSize.height() / 2);
// 绘制炮塔并选择炮塔
// 这里将坐标原点移到m_pos,绘制的适合,就要加上那个偏移点到左上角
painter->translate(m_pos);
painter->drawPixmap(offsetPoint, m_sprite);
painter->restore();

这里由于要改变painter一些设置,因此最好加上save/restore来作恢复使用

这样,就完成了攻击塔的绘制,赶快来解决下点击事件吧,看看效果吧!


为MainWindow重载mousePressEvent和添加canBuyTower处理函数(名字就该清晰了吧,后期需要用钱买,现在先免费)

同时为MainWindow添加成员

QList<Tower *> m_towersList; // 用来管理攻击塔的信息

重点查看下那两个方法呗:

void MainWindow::mousePressEvent(QMouseEvent *event)
{
	QPoint pressPos = event->pos();
	auto it = m_towerPositionsList.begin();
	while (it != m_towerPositionsList.end())
	{
		if (canBuyTower() && it->containPoint(pressPos) && !it->hasTower())
		{
			it->setHasTower();
			Tower *tower = new Tower(it->centerPos(), this);
			m_towersList.push_back(tower);
			update();
			break;
		}

		++it;
	}
}

bool MainWindow::canBuyTower() const
{
	return true;
}

这里auto it = xxx.begin();是用到了C++11的新语法,这个随意啦,需要使用,在pro文件中添加

CONFIG += c++11

这里代码逻辑简单,遍历所有安放位置,点在安放位置 && 有钱(暂时肯定有啦~) && 没有别的塔

就添加入m_towerList管理中,看下效果吧!

还需要在paintEvent中添加相应绘制代码:

foreach (Tower *tower, m_towersList)
	tower->draw(&painter);
之后,可以看下效果图,点中区域,就好了:

现在塔也出来了,nice!

3、为敌人出现做准备,添加敌人行走路线,航点

塔防游戏路线其实不需要什么特别算法,针对本游戏更加简单,左上为入口,右下为基地,路线其实就是这么一个形状,先看效果图:

一共也就6个点,路线也是很正,都是直上直下,直男天下,哈哈

可惜不知道怎么了,原作者给的那几个点我用来都是有问题的,因此自己又重新测了下

下面是我添加的这几点:

void MainWindow::addWayPoints()
{
	WayPoint *wayPoint1 = new WayPoint(QPoint(420, 285));
	m_wayPointsList.push_back(wayPoint1);

	WayPoint *wayPoint2 = new WayPoint(QPoint(35, 285));
	m_wayPointsList.push_back(wayPoint2);
	wayPoint2->setNextWayPoint(wayPoint1);

	WayPoint *wayPoint3 = new WayPoint(QPoint(35, 195));
	m_wayPointsList.push_back(wayPoint3);
	wayPoint3->setNextWayPoint(wayPoint2);

	WayPoint *wayPoint4 = new WayPoint(QPoint(445, 195));
	m_wayPointsList.push_back(wayPoint4);
	wayPoint4->setNextWayPoint(wayPoint3);

	WayPoint *wayPoint5 = new WayPoint(QPoint(445, 100));
	m_wayPointsList.push_back(wayPoint5);
	wayPoint5->setNextWayPoint(wayPoint4);

	WayPoint *wayPoint6 = new WayPoint(QPoint(35, 100));
	m_wayPointsList.push_back(wayPoint6);
	wayPoint6->setNextWayPoint(wayPoint5);
}

这里用一个小封装的WayPoint来存储节点,WayPoint行为像是一个逆序链表,第一点其实是基地,(我比较懒,没有修改,其实觉得用Qt自带容器就可以了,而且为毛要逆序,顺序不就可以了),那个setNextWayPoint,其实存放的也是后一个节点,只不过节点6才是起始节点,蛋疼ing,对于WayPoint不解释了,也是那几点,在MainWindow中也需要管理:

1.声明:

// 敌人移动的航线
class WayPoint
{
public:
	WayPoint(QPoint pos);

	void setNextWayPoint(WayPoint *nextPoint);
	WayPoint* nextWayPoint() const;
	const QPoint pos() const;

	void draw(QPainter *painter) const;

private:
	QPoint m_pos;
	WayPoint * m_nextWayPoint;
};

2.实现

WayPoint::WayPoint(QPoint pos)
	: m_pos(pos)
	, m_nextWayPoint(NULL)
{
}

void WayPoint::setNextWayPoint(WayPoint *nextPoint)
{
	m_nextWayPoint = nextPoint;
}

WayPoint* WayPoint::nextWayPoint() const
{
	return m_nextWayPoint;
}

const QPoint WayPoint::pos() const
{
	return m_pos;
}

void WayPoint::draw(QPainter *painter) const
{
	painter->save();
	painter->setPen(QColor(0, 255, 0));
	painter->drawEllipse(m_pos, 6, 6);
	painter->drawEllipse(m_pos, 2, 2);

	if (m_nextWayPoint)
		painter->drawLine(m_pos, m_nextWayPoint->m_pos);
	painter->restore();
}

3.MainWindow中添加

QList<WayPoint *> m_wayPointsList;	// 在paintEvent中需要进行绘制,那个类似的foreach(xxx) xxx.draw(xxx)
void addWayPoints();			// 在构造函数中调用

这几步曲几乎是后续元素添加的顺序

这里航点是由一个两个圆套起来显示的,敌人会和航点圆心做碰撞检查,碰撞到了,就要开始调换方向,向下一个原点进发


好了,今天太晚了,先写到这里,之后继续~

未完Go on!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/satanzw/article/details/10418063

智能推荐

稀疏编码的数学基础与理论分析-程序员宅基地

文章浏览阅读290次,点赞8次,收藏10次。1.背景介绍稀疏编码是一种用于处理稀疏数据的编码技术,其主要应用于信息传输、存储和处理等领域。稀疏数据是指数据中大部分元素为零或近似于零的数据,例如文本、图像、音频、视频等。稀疏编码的核心思想是将稀疏数据表示为非零元素和它们对应的位置信息,从而减少存储空间和计算复杂度。稀疏编码的研究起源于1990年代,随着大数据时代的到来,稀疏编码技术的应用范围和影响力不断扩大。目前,稀疏编码已经成为计算...

EasyGBS国标流媒体服务器GB28181国标方案安装使用文档-程序员宅基地

文章浏览阅读217次。EasyGBS - GB28181 国标方案安装使用文档下载安装包下载,正式使用需商业授权, 功能一致在线演示在线API架构图EasySIPCMSSIP 中心信令服务, 单节点, 自带一个 Redis Server, 随 EasySIPCMS 自启动, 不需要手动运行EasySIPSMSSIP 流媒体服务, 根..._easygbs-windows-2.6.0-23042316使用文档

【Web】记录巅峰极客2023 BabyURL题目复现——Jackson原生链_原生jackson 反序列化链子-程序员宅基地

文章浏览阅读1.2k次,点赞27次,收藏7次。2023巅峰极客 BabyURL之前AliyunCTF Bypassit I这题考查了这样一条链子:其实就是Jackson的原生反序列化利用今天复现的这题也是大同小异,一起来整一下。_原生jackson 反序列化链子

一文搞懂SpringCloud,详解干货,做好笔记_spring cloud-程序员宅基地

文章浏览阅读734次,点赞9次,收藏7次。微服务架构简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目。这么多小服务,如何管理他们?(服务治理 注册中心[服务注册 发现 剔除])这么多小服务,他们之间如何通讯?这么多小服务,客户端怎么访问他们?(网关)这么多小服务,一旦出现问题了,应该如何自处理?(容错)这么多小服务,一旦出现问题了,应该如何排错?(链路追踪)对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。_spring cloud

Js实现图片点击切换与轮播-程序员宅基地

文章浏览阅读5.9k次,点赞6次,收藏20次。Js实现图片点击切换与轮播图片点击切换<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title></title> <script type="text/ja..._点击图片进行轮播图切换

tensorflow-gpu版本安装教程(过程详细)_tensorflow gpu版本安装-程序员宅基地

文章浏览阅读10w+次,点赞245次,收藏1.5k次。在开始安装前,如果你的电脑装过tensorflow,请先把他们卸载干净,包括依赖的包(tensorflow-estimator、tensorboard、tensorflow、keras-applications、keras-preprocessing),不然后续安装了tensorflow-gpu可能会出现找不到cuda的问题。cuda、cudnn。..._tensorflow gpu版本安装

随便推点

物联网时代 权限滥用漏洞的攻击及防御-程序员宅基地

文章浏览阅读243次。0x00 简介权限滥用漏洞一般归类于逻辑问题,是指服务端功能开放过多或权限限制不严格,导致攻击者可以通过直接或间接调用的方式达到攻击效果。随着物联网时代的到来,这种漏洞已经屡见不鲜,各种漏洞组合利用也是千奇百怪、五花八门,这里总结漏洞是为了更好地应对和预防,如有不妥之处还请业内人士多多指教。0x01 背景2014年4月,在比特币飞涨的时代某网站曾经..._使用物联网漏洞的使用者

Visual Odometry and Depth Calculation--Epipolar Geometry--Direct Method--PnP_normalized plane coordinates-程序员宅基地

文章浏览阅读786次。A. Epipolar geometry and triangulationThe epipolar geometry mainly adopts the feature point method, such as SIFT, SURF and ORB, etc. to obtain the feature points corresponding to two frames of images. As shown in Figure 1, let the first image be ​ and th_normalized plane coordinates

开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先抽取关系)_语义角色增强的关系抽取-程序员宅基地

文章浏览阅读708次,点赞2次,收藏3次。开放信息抽取(OIE)系统(三)-- 第二代开放信息抽取系统(人工规则, rule-based, 先关系再实体)一.第二代开放信息抽取系统背景​ 第一代开放信息抽取系统(Open Information Extraction, OIE, learning-based, 自学习, 先抽取实体)通常抽取大量冗余信息,为了消除这些冗余信息,诞生了第二代开放信息抽取系统。二.第二代开放信息抽取系统历史第二代开放信息抽取系统着眼于解决第一代系统的三大问题: 大量非信息性提取(即省略关键信息的提取)、_语义角色增强的关系抽取

10个顶尖响应式HTML5网页_html欢迎页面-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏51次。快速完成网页设计,10个顶尖响应式HTML5网页模板助你一臂之力为了寻找一个优质的网页模板,网页设计师和开发者往往可能会花上大半天的时间。不过幸运的是,现在的网页设计师和开发人员已经开始共享HTML5,Bootstrap和CSS3中的免费网页模板资源。鉴于网站模板的灵活性和强大的功能,现在广大设计师和开发者对html5网站的实际需求日益增长。为了造福大众,Mockplus的小伙伴整理了2018年最..._html欢迎页面

计算机二级 考试科目,2018全国计算机等级考试调整,一、二级都增加了考试科目...-程序员宅基地

文章浏览阅读282次。原标题:2018全国计算机等级考试调整,一、二级都增加了考试科目全国计算机等级考试将于9月15-17日举行。在备考的最后冲刺阶段,小编为大家整理了今年新公布的全国计算机等级考试调整方案,希望对备考的小伙伴有所帮助,快随小编往下看吧!从2018年3月开始,全国计算机等级考试实施2018版考试大纲,并按新体系开考各个考试级别。具体调整内容如下:一、考试级别及科目1.一级新增“网络安全素质教育”科目(代..._计算机二级增报科目什么意思

conan简单使用_apt install conan-程序员宅基地

文章浏览阅读240次。conan简单使用。_apt install conan