什么是热更新
所谓的热更新,指的是客户端的更新。
大致的流程是,客户端在启动后访问更新的URL接口,根据更新接口的反馈,下载更新资源,然后使用新的资源启动客户端,或者直接使用新资源不重启客户端。
热更新代码使用到的场景
- 情人节快到了,你想要组织一个游戏内活动,错过时机肯定是你最不想要看到的结果。
- 当你发现一个严重的bug。
- 当你想要添加一些新的场景或者关卡来延长游戏的生命。
- 以及非常多其他的情况...
在Cocos2d-x引擎中的如何实现热更新
LuaEngine
LuaEngine是一个脚本能够实时运行Lua脚本的对象,也就是因为有了LuaEngine这个C++类对象,所以才有了实现热更新技术的基础
获取LuaEngine脚本引擎的对象。
//获取LuaEngine引擎脚本类的单例对象
LuaEngine *engine = LuaEngine::getInstance(); //设置该单例对象作为脚本引擎管理器对象的脚本引擎
ScriptEngineManager::getInstance()->setScriptEngine(engine);
使用LuaEngine执行Lua字符串脚本
//使用Lua脚本引擎执行Lua字符串脚本
engine->executeString("print(\"Hello 蓝鸥\")");
使用LuaEngine执行Lua文件脚本
//获取储存的文件路径
std::string path = FileUtils::getInstance()->getWritablePath();
path += "hellolanou.lua"; //创建一个文件指针
//路径、模式
FILE* file = fopen(path.c_str(), "w");
if (file) {
fputs("print (\"蓝鸥!!!\")", file);
fclose(file);
}
else
CCLOG("save file error."); //使用Lua脚本引擎执行Lua文件脚本
engine->executeScriptFile(path.c_str());
lua_State
lua_State,可以认为是“脚本上下文”,主要包括当前Lua脚本环境的运行状态信息,还会有GC相关的信息。
在使用cocos2d-x引擎开发时需要使用Lua,那么就需要连接到libcocos2d和libluacocos2d两个静态库。
也就是要在lua_State对象中注册对应的功能模块类,如果不想要使用里边相应的模块时,就可以在luamoduleregister.h中注释掉对应的一行代码。
int lua_module_register(lua_State* L)
{
//注册cocosdenshion模块
register_cocosdenshion_module(L);
//注册network网络模块
register_network_module(L);
#if CC_USE_CCBUILDER
//注册cocosbuilder模块
register_cocosbuilder_module(L);
#endif
#if CC_USE_CCSTUDIO
//注册coccostudio模块
register_cocostudio_module(L);
#endif
//注册ui模块
register_ui_moudle(L);
//注册extension模块
register_extension_module(L);
#if CC_USE_SPINE
//注册spine模块
register_spine_module(L);
#endif
#if CC_USE_3D
//注册3d模块
register_cocos3d_module(L);
#endif
//注册音频audio模块
register_audioengine_module(L);
return 1;
}
在使用cocos2d-x引擎时需要使用quick框架时,同样需要在lua_State注册quick框架的对应模块。
static void quick_module_register(lua_State *L)
{
luaopen_lua_extensions_more(L); lua_getglobal(L, "_G");
if (lua_istable(L, -1))//stack:...,_G,
{
register_all_quick_manual(L);
// extra
luaopen_cocos2dx_extra_luabinding(L);
register_all_cocos2dx_extension_filter(L);
luaopen_HelperFunc_luabinding(L);
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
luaopen_cocos2dx_extra_ios_iap_luabinding(L);
#endif
}
lua_pop(L, 1);
}
LuaStack
通常情况下每一个lua_State对象就对应一个LuaStack。
使用到的相关代码
//使用LuaEngine对象获取Lua的函数栈
LuaStack* stack = engine->getLuaStack();
#if ANYSDK_DEFINE > 0
lua_getglobal(stack->getLuaState(), "_G");
tolua_anysdk_open(stack->getLuaState());
tolua_anysdk_manual_open(stack->getLuaState());
lua_pop(stack->getLuaState(), 1);
#endif
//设置加密用的密钥
stack->setXXTEAKeyAndSign("2dxLua", strlen("2dxLua"), "XXTEA", strlen("XXTEA"));
AssetsManager
资源管理器的诞生就是为了在游戏运行时能够完成资源热更新的技术而设计的。
这里的资源可以是图片,音频甚至是游戏的脚本本身。
使用资源管理器,你将可以上传新的资源到你的服务器,你的游戏会跟踪远程服务器上的修改,将新的资源下载到用户的设备上并在游戏中使用新的资源。
这样的话,一个全新的设计,全新的游戏体验甚至全新的游戏内容就可以立刻被推送到用户的受伤。
更加重要的是,我们并不需要针对各个渠道去重新打包我们的应用程序并且经历痛苦的应用审核,这个过程中没有任何成本!
创建AssetsManager对象
static AssetsManager *assetManager = NULL; if (!assetManager) {
/*创建AssetsManager对象
*@param 资源包的下载路径
*@param 资源包的当前版本
*@param 资源包下载后的存储路径
*/
assetManager = new AssetsManager(
"http://project.lanou3g.com/game/cocos/teacher/test/src.zip",
"http://project.lanou3g.com/game/cocos/teacher/test/version.php",
_pathToSave.c_str());
//设置AssetsManager对象的回调对象
assetManager->setDelegate(this);
//设置AssetsManager对象的timeout时间
assetManager->setConnectionTimeout(3);
}
AssetsManagerDelegateProtocol
AssetsManagerDelegateProtocal是一个类接口,主要用来封装下载过程中的回调接口。
class AssetsManagerDelegateProtocol
{
public:
virtual ~AssetsManagerDelegateProtocol(){};
public:
/* @brief Call back function for error
@param errorCode Type of error
* @js NA
* @lua NA
*/
virtual void onError(AssetsManager::ErrorCode errorCode) {};
/** @brief Call back function for recording downloading percent
@param percent How much percent downloaded
@warning This call back function just for recording downloading percent.
AssetsManager will do some other thing after downloading, you should
write code in onSuccess() after downloading.
* @js NA
* @lua NA
*/
virtual void onProgress(int percent) {};
/** @brief Call back function for success
* @js NA
* @lua NA
*/
virtual void onSuccess() {};
};
那么接下来,我们使用AssetsManager来创建一个自动更新的类Update.
Update.h
//
// Update.h
// hello
//
// Created by 蓝鸥.
//
// #ifndef __hello__Update__
#define __hello__Update__ #include <stdio.h>
#include "cocos2d.h"
#include "extensions/cocos-ext.h" class Update:public cocos2d::Layer,public cocos2d::extension::AssetsManagerDelegateProtocol
{
public :
Update();
virtual ~Update(); virtual bool init();
void update(cocos2d::Ref *pSender);
void reset(cocos2d::Ref *pSender); //继承的回调函数
virtual void onError(cocos2d::extension::AssetsManager::ErrorCode errorCode);
virtual void onProgress(int percent);
virtual void onSuccess();
CREATE_FUNC(Update); private :
cocos2d::extension::AssetsManager *getAssetsManager();
//创建下载到的目录路径
void initDownloadDir(); private :
std::string _pathToSave;
//用来显示下载进度的Label标签
cocos2d::Label *_showDownloadInfo;
}; #endif /* defined(__hello__Update__) */
Update.cpp
//
// Update.cpp
// hello
//
// Created by 蓝鸥.
//
// #include "Update.h" #if(CC_TARGET_PLATFORM != CC_PLATFORM_WIN32) #include <dirent.h>
#include <sys/stat.h> #endif USING_NS_CC;
USING_NS_CC_EXT; #define DOWNLOAD_FILE "download" #include "CCLuaEngine.h" Update::Update():
_pathToSave(""),
_showDownloadInfo(NULL)
{ } Update::~Update()
{
AssetsManager *assetManager = getAssetsManager();
CC_SAFE_DELETE(assetManager);
} bool Update::init()
{
if (!Layer::init()) {
return false;
} Size winSize = Director::getInstance()->getWinSize(); initDownloadDir(); _showDownloadInfo = Label::createWithSystemFont("", "Arial", 20);
_showDownloadInfo->setPosition(Vec2(winSize.width / 2,winSize.height / 2 - 20));
this->addChild(_showDownloadInfo); auto itemLabel1 = MenuItemLabel::create(
Label::createWithSystemFont("Reset", "Arail", 20), CC_CALLBACK_1(Update::reset, this));
auto itemLabel2 = MenuItemLabel::create(
Label::createWithSystemFont("Update", "Arail", 20), CC_CALLBACK_1(Update::update, this)); auto menu = Menu::create(itemLabel1,itemLabel2, NULL);
this->addChild(menu); itemLabel1->setPosition(Vec2(winSize.width / 2, winSize.height / 2 + 20));
itemLabel2->setPosition(Vec2(winSize.width / 2, winSize.height / 2)); menu->setPosition(Vec2::ZERO); return true;
} void Update::onError(AssetsManager::ErrorCode code)
{
switch (code) {
case cocos2d::extension::AssetsManager::ErrorCode::NO_NEW_VERSION:
_showDownloadInfo->setString("no new version");
break;
case cocos2d::extension::AssetsManager::ErrorCode::NETWORK:
_showDownloadInfo->setString("no new version");
break;
case cocos2d::extension::AssetsManager::ErrorCode::CREATE_FILE:
_showDownloadInfo->setString("create file error");
break;
default:
break;
}
} void Update::onProgress(int percent)
{
if (percent < 0) {
return;
} char progress[20];
snprintf(progress, 20, "download %d%%",percent); _showDownloadInfo->setString(progress);
} void Update::onSuccess()
{
CCLOG("download success"); _showDownloadInfo->setString("download success"); std::string path = FileUtils::getInstance()->getWritablePath() + DOWNLOAD_FILE; LuaEngine* pEngine = LuaEngine::getInstance(); //首先添加下载文件的目录
pEngine->addSearchPath(_pathToSave.c_str()); path += "/src/main.lua"; pEngine->executeScriptFile(path.c_str());
} AssetsManager* Update::getAssetsManager()
{
static AssetsManager *assetManager = NULL; if (!assetManager) {
/*创建AssetsManager对象
*@param 资源包的下载路径
*@param 资源包的当前版本
*@param 资源包下载后的存储路径
*/
assetManager = new AssetsManager(
"http://project.lanou3g.com/game/cocos/teacher/test/src.zip",
"http://project.lanou3g.com/game/cocos/teacher/test/version.php",
_pathToSave.c_str());
//设置AssetsManager对象的回调对象
assetManager->setDelegate(this);
//设置AssetsManager对象的timeout时间
assetManager->setConnectionTimeout(3);
} return assetManager;
} void Update::initDownloadDir()
{
CCLOG("initDownloadDir"); _pathToSave = FileUtils::getInstance()->getWritablePath();
_pathToSave += DOWNLOAD_FILE; CCLOG("Path: %s",_pathToSave.c_str()); #if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
DIR *pDir = NULL; pDir = opendir(_pathToSave.c_str()); if (!pDir) {
mkdir(_pathToSave.c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
}
#else
if ((GetFileAttributes(_pathToSave.c_str())) = INVALID_FILE_ATTRIBUTES) {
CreateDirectoryA(_pathToSave.c_str(),0);
}
#endif CCLOG("initDownloadDir end");
} void Update::reset(Ref *pSender)
{
_showDownloadInfo->setString(""); // Remove downloaded files
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
std::string command = "rm -r ";
// Path may include space.
command += "\"" + _pathToSave + "\"";
system(command.c_str());
#else
std::string command = "rd /s /q ";
// Path may include space.
command += "\"" + _pathToSave + "\"";
system(command.c_str());
#endif getAssetsManager()->deleteVersion();
initDownloadDir();
} void Update::update(Ref *pSender)
{
_showDownloadInfo->setString("");
getAssetsManager()->update();
}
可以点击下载下来网络资源压缩包,看下压缩包内包含的内容。
可以点击下载下来源代码压缩包,对应一起的。
大家最好可以在本地搭建一个apache服务器,做一下练习。
[Cocos2d-x]Lua 资源热更新的更多相关文章
-
Lua------------------unity与lua的热更新
[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新完全解读 标签: 游戏开发游戏解决方案用户体验unity3d 2014-10-18 23:23 7680人阅读 ...
-
Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...
-
Lua的热更新学习笔记_01
热更新的的实现方式 1.使用lua脚本编写游戏的UI或者其他的逻辑 2.使用C#的反射技术 3.使用C#Light AssetBundle是什么? 1.unity提供一个资源更新技术,就是通过Asse ...
-
Unity手游之路<;十二>;手游资源热更新策略探讨
http://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略. ...
-
[unity3d]手游资源热更新策略探讨
原地址:http://blog.csdn.net/dingxiaowei2013/article/details/20079683 我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游 ...
-
[转]Unity手游之路<;十二>;手游资源热更新策略探讨
最近梳理了下游戏流程.恩,本来想写下,但是,还是看前辈的吧 版权声明: https://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何 ...
-
【学习】Unity手游之路<;十二>;手游资源热更新策略探讨
http://blog.csdn.net/janeky/article/details/17666409 =============================================== ...
-
实现iOS图片等资源文件的热更新化(五): 一个简单完整的资源热更新页面
简介 一个简单的关于页面,有一个图片,版本号,App名称等,着重演示各个系列的文章完整集成示例. 动机与意义 这是系列文章的最后一篇.今天抽空写下,收下尾.文章本身会在第四篇的基础上,简单扩充下代码, ...
-
[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新全然解读
---------------------------------------------------------------------------------------------------- ...
随机推荐
-
剑指Offer:面试题8——旋转数组的最小值(java实现)
题目描述: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入 一个递增排序的数组的一个旋转 输出 旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的 ...
-
如何扩大VMware虚拟机的硬盘磁盘空间大小
首先,在虚拟机配置界面通过界面配置,直接扩大虚拟机硬盘大小: 而后,登陆虚拟机,在windows磁盘管理,更多操作中直接“重新扫描磁盘”,操作系统自动找到了多出来的磁盘空间: 最后,在老磁盘分区上通过 ...
-
HDU1247 - Hat&rsquo;s Words(Trie树)
题目大意 给定一些单词,要求你把所有的帽子单词找出来,如果某个单词恰好由另外两个单词连接而成,那么它就是帽子单词 题解 先把所有单词插入到Trie树,然后判断每个单词是不是帽子单词,做法就是:对于第i ...
-
Linux修改时间时区并在Tomcat中生效
Linux查看当前时间时区linux:~ # datelinux:~ # date –Rlinux:~ # zdump -v /usr/share/zoneinfo/Asia/Beijing ---- ...
-
【AtCoder】【DP】【思维】Prefix Median(AGC012)
模的是这位神犇的代码:Atcoder AGC012F : Prefix Median 题意: 在动态中位数那道题上做了一些改动.给你一个序列a,可以将a重新任意排序,然后对于a序列构造出b序列. 假设 ...
-
【概括】C++11/14特性
c++11 c++14
-
SQL NOLOCK大杂烩
今天碰到NOLOCK 的问题,就查阅了一些资料,做了相关了解:总结了比较经典,朴实的两篇在此. 电梯直达: SQL Server 中WITH (NOLOCK)浅析 文章本想大篇幅摘抄,因为担心链接失效 ...
-
《Inside C#》笔记(十二) 委托与事件
C#的委托与C++的函数指针类似,但委托是类型安全的,意味着指针始终会指向有效的函数.委托的使用主要有两种:回调和事件. 一 将委托作为回调函数 在需要给一个函数传递一个函数指针,随后通过函数指针调用 ...
-
XShell安装
Xshell就是一个远程控制Centos的软件:(用XShell比较方便,试用的都知道,界面也人性化) 详细介绍请看 百度百科 下面我们来安装下这个工具: 双击exe 点下一步: 选 免费的 然后下一 ...
-
jqGrid使用json实现的范例一
qGrid 是一个用来显示网格数据的jQuery插件,通过使用jqGrid可以轻松实现前端页面与后台数据的ajax异步通信.文档比较全面,其官方网址为:http://www.trirand.com. ...