文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Qt实现打地鼠游戏的方法详解

2022-11-13 18:13

关注

今天与大家分享一个小游戏的实现:打地鼠

看一下实现效果吧~

在指定的时间内打中一定数额的地鼠,否则失败,就如上述展示效果一样,自己写的小程序,居然连第二关也过不去,还挺尴尬的!

实现打地鼠小游戏不难,最主要的核心就是依靠定时器,按照一定间隔触发。接下来,我来讲解下是如何实现的吧!

功能讲解

开发环境:VS2017 + Qt5.14.2 x64

1.确定地鼠数量

对于打地鼠这款游戏来说,地鼠是从任意的洞口钻出。

在效果中,一共存在6个地鼠洞,最容易实现的方式:创建6个地鼠,每个地鼠洞都对应一个地鼠。

实现代码如下:

for (int i = 0; i < num; i++)
{
	QPushButton *btn = new QPushButton(this);
	int nTop = i / 3 == 0 ? 300 : 450;
	int nRemainder = i % 3;
	if (nRemainder == 0)
	{
		btn->setGeometry(190, nTop, 180, 130);
	}
	else if (nRemainder == 1)
	{
		btn->setGeometry(480, nTop, 180, 130);
	}
	else if(nRemainder == 2)
	{
		btn->setGeometry(780, nTop, 180, 130);
	}
	btn->setStyleSheet(qsBtnStyle);
	btn->setProperty("num", i);
	btn->hide();
	connect(btn, &QPushButton::clicked, this, &QGrameWhacAmole::OnBnClickedSusliks); //选中地鼠
	m_vetBtnCtrls.push_back(btn);
}

代码解析:

num:此刻代表的是6,表明了需要创建6个地鼠,平均分配到每个洞中。

对每个地鼠按钮响应对应的clicked消息,每当打中一个地鼠,OnBnClickedSusliks消息内就对分数+1。

并且,创建出的地鼠默认是隐藏状态的。

2.定义游戏难易程序

在程序中定义了四种难度,设置了枚举类型:

enum ENUM_GameMode
{
	GameMode_difficulty1,
	GameMode_difficulty2,
	GameMode_difficulty3, 
	GameMode_difficulty4, 
	GameMode_OK,
	GameMode_Failed,
};

GameMode_difficulty1:难度1,说明有1个地鼠出没

GameMode_difficulty2:难度2,说明有2个地鼠出没,

GameMode_difficulty3:难度3,说明有3个地鼠出没,

GameMode_difficulty4:难度4,说明有4个地鼠出没

在程序中,如何判断通过某一关呢?

宏定义确定通关分数

#define  difficulty1Count 10 //难度1个数
#define  difficulty2Count 30 
#define  difficulty3Count 60
#define  difficulty4Count 100

当第一关时,只需要打中10个地鼠;第二关需要累计打中30个地鼠,以此类推。

3.难度切换

在OnBnClickedSusliks消息中,根据当前的分数来确定是否要晋级。

响应消息后,对分数进行+1处理

m_nScore += 1;

m_nScore是当前类的成员变量,表示:打中的地鼠次数也就是当前分数。

打中后隐藏该地鼠

当打中某个地鼠后,需要立刻隐藏地鼠,此时就运用到了刚刚在创建地鼠时"setProperty"绑定的变量了。

QPushButton *btn = qobject_cast<QPushButton*>(sender());
int num = btn->property("num").toInt();
m_vetBtnCtrls[num]->hide(); //隐藏对应编号控件

分数判断是否晋级

当分数到达难度1时,晋升成难度2,其它的关卡都一样

if (m_nScore == difficulty1Count) //难度1通过
{
	killTimer(m_nTimerStartId);
	m_nTimerStartId = 0;

	this->HideTotalSucliks();
		
	m_enumMode = GameMode_difficulty2;
	this->SetTipsStyle(m_enumMode);

	m_nTimerStartId = startTimer(difficulty2Time);
	m_dwBeginTime = GetTickCount();
}

当通过第一关后,停止定时器,隐藏正在展示的所有地鼠,更改模式状态,重新设置提示文本,开始定时器,重新记录开始通关时间。

m_dwBeginTime:是记录每次开始游戏时的时间,主要作用于挑战失败的判断,也就是说,每次触发定时器时,当前最新时间与最开始通关时间的差值 大于 通关时间时,说明当前关卡挑战失败!

4.定时器处理

这也是当前小游戏中最核心的处理部分了~

为了方便起见,直接使用QWidget自带的定时器,而不是使用new QTimer的方式

virtual void timerEvent(QTimerEvent *event);

在定时器的处理中,分成了4部分,我们分别讲述~

获取定时器Id的触发消息

if (event->timerId() == m_nTimerStartId)
{
    //消息处理
}

只有当定时器的触发id与我们设定的id一致时,才可以。

关闭提示页面

在进行难度切换时,设置了提示文本,也就是效果图中的“开始”、“开始第二关”等文字提示信息,在进入到定时器事件中,首先判断,该控件是否隐藏?如果未隐藏,先进行隐藏。

if (ui.labTips->isHidden() == false)
{
	ui.labTips->hide();
}

在这里需要我走过一个坑:使用isVisible()不一定获取出控件的显示状态,但是isHidden()始终是有效的

判断当前关卡是否超时?

这也就是上文说到的m_dwBeginTime与最新触发时间的差值

DWORD dwTime = GetTickCount() - m_dwBeginTime;
if (dwTime > difficultyTimeout)
{
	this->RunningFailed();
}

根据关卡不同,显示不同的地鼠

这里,就是对地鼠显示的逻辑处理了,根据枚举模式不同,分别处理

switch (m_enumMode)
{
case QGrameWhacAmole::GameMode_difficulty1:
	this->RunningGamedifficulty(1);
break;
case QGrameWhacAmole::GameMode_difficulty2:
	this->RunningGamedifficulty(2);
break;
case QGrameWhacAmole::GameMode_difficulty3:
	this->RunningGamedifficulty(3);
break;
case QGrameWhacAmole::GameMode_difficulty4:
	this->RunningGamedifficulty(4);
break;
default:
break;
}

核心函数是:RunningGamedifficulty

如何让地鼠进行随机显示呢?

在当前例子中,获取随机数[0,6)之间的值,随机到哪个数,哪个下标下对应的地鼠被显示,其余的地鼠处于隐藏状态。

随机数生成方法:

int QGrameWhacAmole::GetRandomNumber()
{
	QTime time = QTime::currentTime();
	qsrand(time.msec() + time.second() * 1000);
	int n = qrand() % 6;
	return n;
}

有人说使用这种方法可以在短时间内生成的随机数不相同,这个方法我已经验证过了,不行!

还有的人说可以添加sleep,我也尝试过了,不行!

那么,该如何获取不重复的随机数呢?

在这里,采用了std::set<int>容器的方式,RunningGamedifficulty中的部分代码如下:

void QGrameWhacAmole::RunningGamedifficulty(int nCount)
{
    1:随机数生成
    std::set<int> setRandom; //存储随机数
    for (int i = 0; setRandom.size() < nCount; i++)
    {
	//获取随机数
	int num = this->GetRandomNumber();
	//如果随机数在容器中从未出现过,存储并应用
	if (setRandom.size() != 0)
	{
		std::set<int>::iterator itFind = setRandom.find(num);
		if (itFind != setRandom.end())
		{
			continue; //存在重复值,后续不进行处理
		}
	}
	//容器中存在数据,存储之前进行判断
	setRandom.insert(num);
     }
        
        
}

根据上述代码也可以看出,每生成一个随机数,就进行存储,当容器中出现相同的随机数时,重新生成。

nCount:就是需要展示的地鼠个数,在for循环中,中间的判断条件与以往不同,当有效地地鼠编号大于地鼠个数后,就不再获取随机数了。

这种方式,无论是获取多少个地鼠个数都是适用的。

其次,根据获取的显示的地鼠下标数就可以对所有的地鼠进行做显示、隐藏操作了,代码如下:

for (int m = 0; m < m_vetBtnCtrls.size(); m++)
{
	std::set<int>::iterator itNum = setRandom.find(m);
	if (itNum != setRandom.end())
	{
		m_vetBtnCtrls[m]->show();
	}
	else
	{
		m_vetBtnCtrls[m]->hide();
	}
}

总结

到这里,核心的实现功能就已经讲解完了,功能难点:

1:根据地鼠个数随机显示地鼠位置(RunningGamedifficulty处理逻辑)。

2:关卡晋级。

3:挑战失败处理。

到此这篇关于Qt实现打地鼠游戏的方法详解的文章就介绍到这了,更多相关Qt打地鼠游戏内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯