什么是热更新

所谓的热更新,指的是客户端的更新。

大致的流程是,客户端在启动后访问更新的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 资源热更新的更多相关文章

  1. Lua------------------unity与lua的热更新

    [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新完全解读 标签: 游戏开发游戏解决方案用户体验unity3d 2014-10-18 23:23 7680人阅读 ...

  2. Unity3D热更新之LuaFramework篇[09]--资源热更新与代码热更新的具体实现

    前言 在上一篇文章 Unity3D热更新之LuaFramework篇[08]--热更新原理及热更服务器搭建 中,我介绍了热更新的基本原理,并且着手搭建一台服务器. 本篇就做一个实战练习,真正的来实现热 ...

  3. Lua的热更新学习笔记_01

    热更新的的实现方式 1.使用lua脚本编写游戏的UI或者其他的逻辑 2.使用C#的反射技术 3.使用C#Light AssetBundle是什么? 1.unity提供一个资源更新技术,就是通过Asse ...

  4. Unity手游之路<十二>手游资源热更新策略探讨

    http://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略. ...

  5. [unity3d]手游资源热更新策略探讨

    原地址:http://blog.csdn.net/dingxiaowei2013/article/details/20079683 我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游 ...

  6. [转]Unity手游之路<十二>手游资源热更新策略探讨

    最近梳理了下游戏流程.恩,本来想写下,但是,还是看前辈的吧 版权声明: https://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何 ...

  7. 【学习】Unity手游之路<十二>手游资源热更新策略探讨

    http://blog.csdn.net/janeky/article/details/17666409 =============================================== ...

  8. 实现iOS图片等资源文件的热更新化(五): 一个简单完整的资源热更新页面

    简介 一个简单的关于页面,有一个图片,版本号,App名称等,着重演示各个系列的文章完整集成示例. 动机与意义 这是系列文章的最后一篇.今天抽空写下,收下尾.文章本身会在第四篇的基础上,简单扩充下代码, ...

  9. [Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新全然解读

    ---------------------------------------------------------------------------------------------------- ...

随机推荐

  1. 转 : net use的使用

    老是忘了 net use 怎么样,今天在网上找一篇,贴在这,感谢原作者分享.     1 查看远程主机的共享资源(但看不到默认共享) net view \\IP 2向远程主机复制文件 copy \路径 ...

  2. Android OpenGL ES(十四)gl10方法解析

    Android 支持 OpenGL 列表 1.GL 2.GL 10 3.GL 10 EXT 4.GL 11 5.GL 11 EXT 6.GL 11 ExtensionPack 我们将使用 GL10 这 ...

  3. POJ 1067 取石子游戏 威佐夫博弈

    威佐夫博弈(Wythoff Game):有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜. 我们用(ak,bk)(ak ≤ bk ,k= ...

  4. 关于Arduino 步进电机Stepper库的一些想法

    官方提供了一些库,使Arduino入门起来更加快速,我们连原理都不用懂,就能通过函数控制终端.但是,这样也带来了很多的缺陷,比如,库函数的功能有限,有些无法实现.然后还有库函数因为要考虑其他的情况,你 ...

  5. Python -- OOP高级 -- 枚举类

    Enum可以把一组相关常量定义在一个class中,且class不可变,而且成员可以直接比较. from enum import Enum Month = Enum('Month', ('Jan', ' ...

  6. android 5.0新特性学习--RecyclerView

    在过去很多年,我们的PC或者手机设备都是采用拟物化的设计风格,IOS采用扁平化的特性,android在2014年IO大会上说采用Material Design的设计风格,显示效果不能过于生硬的转换,而 ...

  7. L5,no wrong numbers

    expressions: up to now,到现在为止 a great many,数量很大 in a way,在某种意义上说   words: burn,vt燃烧,vi烧毁,n灼烧 obtain,v ...

  8. HDU 1890 Robotic Sort | Splay

    Robotic Sort Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) [Pr ...

  9. cordova 启动界面config.xml配置

    <preference name="SplashScreen" value="screen"/> <preference name=" ...

  10. jq判断元素是否显示

    为了判断元素是否显示,jquery中用is()来实现, $(function(){ $(obj).bind('click',function(){ if(obj.is(:visible)){ //编写 ...