(十一)C++自制植物大战僵尸游戏客户端更新实现

news2024/12/23 18:45:56

植物大战僵尸游戏开发教程专栏地址icon-default.png?t=N7T8http://t.csdnimg.cn/cFP3z


更新检查

游戏启动后会下载服务器中的版本号然后与本地版本号进行对比,如果本地版本号小于服务器版本号就会弹出更新提示。让用户选择是否更新客户端。

在弹出的更新对话框中有显示最新版本更新的内容,以及更新按钮等。用户可以选择更新方式或者进行更新。


文件位置 

代码文件实现位置在Class\Scenes\MainMenuScene文件夹中。 


UpdateClient.h 

客户端更新类继承与对话框类(Dialog),因为客户端更新也是一个对话对话框供玩家操作。UpdateClient头文件定义如下。

class UpdateClient :public Dialog
{
public:
    CREATE_FUNC(UpdateClient);

CC_CONSTRUCTOR_ACCESS:
    UpdateClient();
    virtual bool init();

private:
    enum class Update_Button
    {
        百度网盘下载,
        腾讯微云下载,
        直接下载,
		退出游戏,
        确定
    };
    void createDiglog();	                                                       /* 创建对话框 */
    void createButton(const std::string& name, Vec2& vec2, Update_Button button);  /* 创建按钮 */
    void showText();
    void addScrollView();
    void addMouseEvent();
    void downloadHistoryText();
    void downloadData();
    void downloadProgress();
    void downloadSuccess();
    void downloadError();

private:
    Sprite* _dialog;    /* 对话框 */
    std::unique_ptr<network::Downloader> _downloader;
    Label* _remindText;
    Label* _progressText;
    Label* _explanText;
    Label* _historyText;
    Sprite* _loadBarBackground;
    ui::LoadingBar* _loadingBar;
    ui::ScrollView* _textScrollView;
    bool _isNewDowndload;
};

UpdateClient.cpp

构造函数

在构造函数中对变量进行初始化操作。

UpdateClient::UpdateClient() :
	_dialog(nullptr)
	, _remindText(nullptr)
	, _progressText(nullptr)
	, _explanText(nullptr)
	, _loadBarBackground(nullptr)
	, _loadingBar(nullptr)
	, _historyText(nullptr)
	, _isNewDowndload(true)
{
	_downloader.reset(new network::Downloader());
}

init函数

创建游戏更新对话框,首先会调用init函数。在init函数中首先会在场景中创建一个黑色半透明的遮罩层,使用场景变黑,让玩家聚焦到此对话框中。然后调用createShieldLayer(this)函数屏蔽除本层之外的所以事件监听,该函数的实现在自定义对话框教程(教程九)中有介绍,作用是让玩家只能和该对话框进行交互。最后使用createDialog()函数创建更新菜单。

bool UpdateClient::init()
{
	if (!LayerColor::initWithColor(Color4B(0, 0, 0, 180)))return false;
	createShieldLayer(this);

	createDialog();
	return true;
}

createDialog()函数

在该函数中主要实现整个更新菜单的界面。

void UpdateClient::createDialog()
{
	_dialog = Sprite::createWithSpriteFrameName("LevelObjiectivesBg.png");
	_dialog->setPosition(_director->getWinSize() / 2);
	_dialog->setScale(0.9f);
	this->addChild(_dialog);

    /* 创建触摸监听 */
	createTouchtListener(_dialog);

	auto PauseAnimation = SkeletonAnimation::createWithData(_global->userInformation->getAnimationData().find("PauseAnimation")->second);
	PauseAnimation->setAnimation(0, "animation", true);
	PauseAnimation->setPosition(Vec2(530, 650));
	_dialog->addChild(PauseAnimation);

	showText();

	createButton(_global->userInformation->getGameText().find("百度网盘下载")->second, Vec2(165, 100), Update_Button::百度网盘下载);
	createButton(_global->userInformation->getGameText().find("腾讯微云下载")->second, Vec2(405, 100), Update_Button::腾讯微云下载);
	createButton(_global->userInformation->getGameText().find("直接下载")->second, Vec2(645, 100), Update_Button::直接下载);
	createButton(_global->userInformation->getGameText().find("关闭游戏")->second, Vec2(885, 100), Update_Button::退出游戏);
	createButton(_global->userInformation->getGameText().find("确定")->second, Vec2(520, 100), Update_Button::确定);

}

创建更新菜单背景,设置位置到屏幕中心,缩放0.9倍大小。 

_dialog = Sprite::createWithSpriteFrameName("LevelObjiectivesBg.png");
_dialog->setPosition(_director->getWinSize() / 2);
_dialog->setScale(0.9f);
this->addChild(_dialog);

对创建好的背景进行触摸监听,可以实现更新菜单的拖动。 

/* 创建触摸监听 */
createTouchtListener(_dialog);

 显示文字内容以及创建多个按钮。

showText();

createButton(_global->userInformation->getGameText().find("百度网盘下载")->second, Vec2(165, 100), Update_Button::百度网盘下载);
createButton(_global->userInformation->getGameText().find("腾讯微云下载")->second, Vec2(405, 100), Update_Button::腾讯微云下载);
createButton(_global->userInformation->getGameText().find("直接下载")->second, Vec2(645, 100), Update_Button::直接下载);
createButton(_global->userInformation->getGameText().find("关闭游戏")->second, Vec2(885, 100), Update_Button::退出游戏);
createButton(_global->userInformation->getGameText().find("确定")->second, Vec2(520, 100), Update_Button::确定);

downloadData()函数

客户端内文件下载更新函数。创建文件下载进度条以及文字信息。

void UpdateClient::downloadData()
{
	if (!_loadBarBackground)
	{
		_loadBarBackground = Sprite::createWithSpriteFrameName("bgFile.png");
		_loadBarBackground->setPosition(Vec2(_dialog->getContentSize().width / 2.f, _dialog->getContentSize().height / 2.f - 100));
		_loadBarBackground->setScale(1.5f);
		_dialog->addChild(_loadBarBackground);
	}

	if (!_loadingBar)
	{
		_loadingBar = ui::LoadingBar::create();
		_loadingBar->loadTexture("progressFile.png", TextureResType::PLIST);
		_loadingBar->setDirection(LoadingBar::Direction::LEFT); /* 设置加载方向 */
		_loadingBar->setPercent(0);
		_loadingBar->setScale(1.5f);
		_loadingBar->setPosition(Vec2(_dialog->getContentSize().width / 2.f, _dialog->getContentSize().height / 2.f - 100));
		_dialog->addChild(_loadingBar);
	}

	_explanText->setColor(Color3B::BLACK);
	_explanText->setString("");

	const static string sNameList = _global->userInformation->getGameText().find("资源名称")->second + UserInformation::getNewEditionName(true) + ".rar";
	const static string path = _global->userInformation->getGameText().find("存放路径")->second + sNameList;

	_downloader->createDownloadFileTask(_global->userInformation->getGameText().find("资源网址")->second, path, sNameList);
	
	downloadProgress();
	downloadSuccess();
	downloadError();
}

创建下载任务,传入服务器文件地址 、文件路径、文件名称。

_downloader->createDownloadFileTask(_global->userInformation->getGameText().find("资源网址")->second, path, sNameList);

调用下载进度、下载成功、下载失败函数 。下载过程会调用downloadProgress()函数,下载成功调用downloadSuccess()函数,下载失败调用downloadError()函数。

downloadProgress();
downloadSuccess();
downloadError();

downloadProgress()函数

onTaskProgress lamda函数中,会实时计算下载进度,bytesReceived参数是当前下载的文大小,totalBytesExpected是文件总大小,totalBytesReceived是总下载大小。通过这三个参数可以计算下载完成所需事件。

void UpdateClient::downloadProgress()
{
	_downloader->onTaskProgress = [=](const network::DownloadTask& task,
		int64_t bytesReceived,
		int64_t totalBytesReceived,
		int64_t totalBytesExpected)
	{
		_explanText->setString(_global->userInformation->getGameText().find("解释说明_慢")->second);

		float percent = float(totalBytesReceived * 100) / totalBytesExpected;
		_loadingBar->setPercent(percent);

		int hour = (totalBytesExpected - totalBytesReceived) / (bytesReceived * 10) / 3600;
		int min = ((totalBytesExpected - totalBytesReceived) / (bytesReceived * 10) - hour * 3600) / 60;
		int second = (totalBytesExpected - totalBytesReceived) / (bytesReceived * 10) - hour * 3600 - min * 60;

		char buf[128];
		if (bytesReceived / 1024.f * 10 >= 1000)
		{
			std::snprintf(buf, 128, "%.1fMB/s  %dKB/%dKB  %.2f%%  time:%02d:%02d:%02d",
					bytesReceived / 1024.f / 1024.f * 10, int(totalBytesReceived / 1024), int(totalBytesExpected / 1024), percent, hour, min, second);
			_progressText->setString(buf);
		}
		else
		{
			std::snprintf(buf, 128, "%.1fKB/s  %dKB/%dKB  %.2f%%  time:%02d:%02d:%02d",
					bytesReceived / 1024.f * 10, int(totalBytesReceived / 1024), int(totalBytesExpected / 1024), percent, hour, min, second);
			_progressText->setString(buf);
		}

		_remindText->setString(_global->userInformation->getGameText().find("文件正在下载中!请稍等!")->second);
    };
}

downloadSuccess()函数

成功下载文件后会调用onFileTaskSuccess lamda函数。在函数中显示下载成功文字信息,将按钮隐藏,然后提示用户退出重新启动游戏。

void UpdateClient::downloadSuccess()
{
	_downloader->onFileTaskSuccess = [this](const cocos2d::network::DownloadTask& task)
	{
		_progressText->setString(_global->userInformation->getGameText().find("下载成功")->second +
			_global->userInformation->getGameText().find("存放路径")->second + task.identifier + " ]");
		_remindText->setString(_global->userInformation->getGameText().find("点击确定退出游戏!")->second);
		_explanText->setString(_global->userInformation->getGameText().find("下载成功说明")->second);

		((Button*)_dialog->getChildByName("0"))->setVisible(false);
		((Button*)_dialog->getChildByName("1"))->setVisible(false);
		((Button*)_dialog->getChildByName("2"))->setVisible(false);
		((Button*)_dialog->getChildByName("3"))->setVisible(false);
		((Button*)_dialog->getChildByName("4"))->setVisible(true);
	};
}

downloadError()函数

如果下载失败,会调用onTaskError lamda函数,在函数中先错误信息提示用户。errorCode的是错误代码,errorStr是错误信息,errorCodeInternal是内部错误代码。

void UpdateClient::downloadError()
{
	_downloader->onTaskError = [this](const cocos2d::network::DownloadTask& task,
		int errorCode,
		int errorCodeInternal,
		const std::string& errorStr)
	{
		_remindText->setString(_global->userInformation->getGameText().find("下载失败")->second);
		((Button*)_dialog->getChildByName("2"))->setEnabled(true);
		((Button*)_dialog->getChildByName("3"))->setEnabled(true);

		char str[256];
		snprintf(str, 256, "Failed to download : 资源文件, identifier(%s) error code(%d), internal error code(%d) desc(%s) 请检查网络连接是否正常!如果网络连接正常请多试几次!或更换其他方式下载!"
			, task.identifier.c_str()
			, errorCode
			, errorCodeInternal
			, errorStr.c_str());
		_explanText->setString(str);
		_explanText->setColor(Color3B::RED);
#ifdef DEBUG
		log("Failed to download : %s, identifier(%s) error code(%d), internal error code(%d) desc(%s)"
			, task.requestURL.c_str()
			, task.identifier.c_str()
			, errorCode
			, errorCodeInternal
			, errorStr.c_str());
#endif // DEBUG
    };
}

其他函数

showText()、createButton()、addScrollView()、addMouseEvent()等函数不再一一列举,可自行查看。

void UpdateClient::showText()
{
	addScrollView();
	_historyText = Label::createWithTTF(_global->userInformation->getGameText().find("更新信息加载中!")->second, GAME_FONT_NAME_1, 50);
	_historyText->setAnchorPoint(Vec2::ANCHOR_MIDDLE_TOP);
	_historyText->setColor(Color3B::BLACK);
	_historyText->setMaxLineWidth(650); 
	_textScrollView->addChild(_historyText);
	_textScrollView->setInnerContainerSize(_historyText->getContentSize());
	_historyText->setPosition(Vec2(_dialog->getContentSize().width / 2.f - 150, _textScrollView->getInnerContainerSize().height - 150));
	downloadHistoryText();

	/* 标题 */
	_remindText = Label::createWithTTF(_global->userInformation->getGameText().find("检测到有新版本,请选择更新方式!")->second, GAME_FONT_NAME_1, 50);
	_remindText->setPosition(Vec2(_dialog->getContentSize().width / 2.f, _dialog->getContentSize().height / 2.f + 200));
	_remindText->setColor(Color3B::BLACK);
	_remindText->setMaxLineWidth(900);
	_remindText->setName("Update");
	_dialog->addChild(_remindText);

	/* 进度文字 */
	_progressText = Label::createWithTTF("", GAME_FONT_NAME_1, 25);
	_progressText->setMaxLineWidth(900);
	_progressText->setPosition(Vec2(_dialog->getContentSize().width / 2.f, _dialog->getContentSize().height / 2.f));
	_dialog->addChild(_progressText);

	/* 说明文字 */
    _explanText = Label::createWithTTF("", GAME_FONT_NAME_1, 30);
	_explanText->setPosition(Vec2(_dialog->getContentSize().width / 2.f, _dialog->getContentSize().height / 2.f + 100));
	_explanText->setColor(Color3B::BLACK);
	_explanText->setMaxLineWidth(900);
	_dialog->addChild(_explanText);
}

void UpdateClient::addScrollView()
{
	_textScrollView = ui::ScrollView::create();
	_textScrollView->setDirection(ui::ScrollView::Direction::VERTICAL);
	_textScrollView->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
	_textScrollView->setContentSize(Size(720.0f, 320.0f));
	_textScrollView->setPosition(_dialog->getContentSize() / 2.0f);
	_textScrollView->setBounceEnabled(true);
	_textScrollView->setScrollBarPositionFromCorner(Vec2(20, 0));
	_textScrollView->setScrollBarWidth(10);
	_textScrollView->setScrollBarColor(Color3B::BLACK);
	_dialog->addChild(_textScrollView);
	addMouseEvent();
}

void UpdateClient::addMouseEvent()
{
	/* 鼠标滑动监听 */
	auto mouse = EventListenerMouse::create();
	mouse->onMouseScroll = [=](Event* event)
	{
		auto mouseEvent = static_cast<EventMouse*>(event);
		float movex = mouseEvent->getScrollY() * 5;

		auto minOffset = 0.f;
		auto maxOffset = 100.f;

		auto offset = _textScrollView->getScrolledPercentVertical();
		offset += movex;

		if (offset < minOffset)
		{
			offset = minOffset;
		}
		else if (offset > maxOffset)
		{
			offset = maxOffset;
		}
		_textScrollView->scrollToPercentVertical(offset, 0.5f, true);
	};
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(mouse, _textScrollView);
}

void UpdateClient::downloadHistoryText()
{
	const string sURLList = _global->userInformation->getGameText().find("更新信息网址")->second;
	_downloader->createDownloadDataTask(sURLList);
	_downloader->onDataTaskSuccess = [this](const cocos2d::network::DownloadTask& task,
		std::vector<unsigned char>& data)
	{
		string historyNetWork;
		for (auto p : data)
		{
			historyNetWork += p;
		}

		TTFConfig ttfConfig(GAME_FONT_NAME_1, 25, GlyphCollection::DYNAMIC);
		_historyText->setTTFConfig(ttfConfig);
		_historyText->setString(historyNetWork);
		_textScrollView->setInnerContainerSize(_historyText->getContentSize());
		_historyText->setPosition(Vec2(350, _textScrollView->getInnerContainerSize().height));
	};
	_downloader->onTaskError = [this](const cocos2d::network::DownloadTask& task,
		int errorCode,
		int errorCodeInternal,
		const std::string& errorStr)
	{
		_historyText->setString(_global->userInformation->getGameText().find("更新信息加载失败!")->second);
		_textScrollView->setInnerContainerSize(_historyText->getContentSize());
	};
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1601666.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全球化背景下的海外社媒营销战略:趋势洞察与策略调整

随着全球化的不断深入&#xff0c;企业在海外市场的竞争愈发激烈。在这一背景下&#xff0c;海外社交媒体平台成为了企业品牌推广和营销的重要渠道。本文Nox聚星将和大家探讨全球化背景下&#xff0c;企业如何利用海外社交媒体平台进行品牌推广和营销&#xff0c;并分析企业如何…

Git分布式版本控制系统——在IDEA中使用Git(一)

一、在IDEA中配置Git 本质上还是使用的本地安装的Git软件&#xff0c;所以需要在IDEA中配置Git 打开IDEA的设置页面&#xff0c;按照下图操作 二、在IDEA中使用Git获取仓库 1、本地初始化仓库 2、从远程仓库克隆 方法一&#xff1a; 方法二&#xff1a; 三、.gitignore文件…

#陶晶驰串口屏使用

1.陶晶驰串口屏输入要连接的wifi信息实现 &#xff08;1&#xff09;选择文本控件 &#xff08;2&#xff09;给文本控件配置输入键盘&#xff0c;id代表用户名&#xff0c;password代表wifi密码&#xff08;注意wifi的频段需要为2.4GHz&#xff09; &#xff08;3&#xff0…

k8s之etcd

1.特点&#xff1a; etcd 是云原生架构中重要的基础组件。有如下特点&#xff1a; 简单&#xff1a;安装配置简单&#xff0c;而且提供了 HTTP API 进行交互&#xff0c;使用也很简单键值对存储&#xff1a;将数据存储在分层组织的目录中&#xff0c;如同在标准文件系统中监…

RAG (Retrieval Augmented Generation) 结合 LlamaIndex、Elasticsearch 和 Mistral

作者&#xff1a;Srikanth Manvi 在这篇文章中&#xff0c;我们将讨论如何使用 RAG 技术&#xff08;检索增强生成&#xff09;和 Elasticsearch 作为向量数据库来实现问答体验。我们将使用 LlamaIndex 和本地运行的 Mistral LLM。 在开始之前&#xff0c;我们将先了解一些术…

性能工具之emqtt-bench BenchMark 测试示例

文章目录 一、前言二、典型压测场景三、机器准备四、典型压测场景1、并发连接2、消息吞吐量测试2.1 1 对 1&#xff08;示例&#xff09;2.2 多对1&#xff08;示例&#xff09;2.3 1对多&#xff08;示例&#xff09; 五、遇到的问题client(): EXIT for {shutdown,eaddrnotava…

OpenStack镜像管理与制作

一、OpenStack镜像服务 1、什么是镜像 镜像通常是指一系列文件或一个磁盘驱动器的精确副本。虚拟机所使用的虚拟磁盘&#xff0c;实际上是一种特殊格式的镜像文件。云环境下尤其需要镜像。镜像就是一个模板&#xff0c;类似于VMware的虚拟机模板&#xff0c;其预先安装基本的…

五步教你正确申请免费SSL证书

在当今数字化时代&#xff0c;保护网站数据安全和提升用户信任至关重要&#xff0c;而实现这一目标的有效途径之一便是为网站部署SSL&#xff08;Secure Sockets Layer&#xff09;证书。SSL证书能够加密网站与用户之间的通信&#xff0c;确保敏感信息不被第三方窃取。幸运的是…

1.8.5 卷积神经网络近年来在结构设计上的主要发展和变迁——Inception-v4 和 Inception-ResNet

1.8.5 卷积神经网络近年来在结构设计上的主要发展和变迁——Inception-v4 和 Inception-ResNet 前情回顾&#xff1a; 1.8.1 卷积神经网络近年来在结构设计上的主要发展和变迁——AlexNet 1.8.2 卷积神经网络近年来在结构设计上的主要发展和变迁——VGGNet 1.8.3 卷积神经网络近…

一篇安装配置ubuntu22.04(步骤详细,配置成功)

一篇配置ubuntu22.04(步骤详细&#xff0c;配置成功) 官网下载相应的镜像 vitualbox安装ubuntu 新建虚拟机 第一步 第二步 第三步、按需分配内存、处理器个数、磁盘大小 第四步、一直下一步直至完成 配置虚拟机网络 第一步、先停止虚拟机 第二步、设置虚拟机网络 正常启…

浅谈Java JVM

Java虚拟机&#xff08;Java Virtual Machine&#xff0c;简称JVM&#xff09;是Java语言的核心组成部分&#xff0c;它是一个抽象的计算机&#xff0c;负责执行Java字节码指令。JVM是Java平台无关性的基石&#xff0c;它为Java代码提供了一个标准的运行环境&#xff0c;使Java…

stable diffusion--小白学习步骤

1.看一下Unet网络的讲解_哔哩哔哩_bilibili&#xff0c;了解Unet网络 2.看一下【生成式AI】Diffusion Model 原理剖析 (1/4)_哔哩哔哩_bilibili&#xff0c;起码要看前3/6个视频 3.看一下超详细的扩散模型&#xff08;Diffusion Models&#xff09;原理代码 - 知乎 (zhihu.co…

关于Ubuntu Server root用户的坑

1 ubuntu server root 用户 ubuntu server 安装过程中会有这个界面&#xff0c;这个界面会比较烦人&#xff0c;让你必须创建一个非root用户&#xff0c;然后只能用这个用户登录&#xff0c;登录上去之后又没有root权限。 输入上一步创建的用户名和密码 登录成功之后&#xff0…

VS Code 前端个人常用扩展分享

这里总结一下 VS Code 里自己开发常用的一些扩展&#xff0c;分三类&#xff1a;基础的&#xff0c;进阶的&#xff0c;工作相关的 一、基础类 首先就是代码拼写检查&#xff0c;引入&#xff0c;辅助开发的一些扩展 语言包 Chinese (Simplified) (简体中文) Language Pack…

重生奇迹mu恶魔来袭副本

在游戏重生奇迹mu中&#xff0c;恶魔来袭副本是玩家能够组队通过的副本。但是因为手游组队的不方便性&#xff0c;部分玩家对其还是非常苦手。而今天&#xff0c;我们就给大家讲解一下这个游戏的双人通关攻略。 1、挂机找怪手动输出 (1)对于普通剧情副本而言&#xff0c;挂机…

HA-Maleimide-HA马来酰亚胺修饰透明质酸 水凝胶递送药物

HA-Maleimide-HA马来酰亚胺修饰透明质酸 水凝胶递送药物 【中文名称】马来酰亚胺修饰透明质酸 【英文名称】HA-Maleimide 【分 子 量】3k/5k/7k/10k/50k/100k/200k/300k/500k/1000k...... 【结 构 式】 【品 牌】碳水科技&#xff08;Tanshtech&#xff09; 【纯 度…

模型微调与迁移学习:实现领域适应性评估

源自&#xff1a;大数据AI人工智能 作者&#xff1a;禅与计算机程序设计艺术 1. 背景介绍 1.1 机器学习的挑战 在机器学习领域&#xff0c;我们通常面临着许多挑战&#xff0c;如数据量不足、数据不平衡、模型泛化能力不足等。为了解决这些问题&#xff0c;研究人员提出了许…

【结构型模式】组合模式

一、组合模式概述 组合模式的定义与意图&#xff1a;将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。&#xff08;对象结构型&#xff09; 组合模式分析&#xff1a; 1.当容器对象的某一个方法被调用时&#xff0c;将遍…

鸿蒙入门02-首次安装和配置

注&#xff1a;还没有安装编辑器&#xff08; deveco studio &#xff09;的小伙伴请看鸿蒙入门01-下载和安装-CSDN博客 首次安装配置 编辑器&#xff08; deveco studio &#xff09;安装完毕以后需要进入配置界面进行相关配置配置完毕以后才可以正常使用 环境配置&#xf…

js处理给标题添加搜索词高亮,标题不包含内容包含的拼接内容包含字样

项目场景&#xff1a; 在项目中我们经常会写搜索&#xff0c;搜索后显示的数据要么标题包含搜索词要么内容包含搜索词&#xff0c;所以我们需要写出下面的效果! 问题描述 数据是后台给的&#xff0c;标题内容是文字样式&#xff0c;所以我们需要在请求完数据后&#xff0c;给…