[Cocos2d-x]Lua 资源热更新

什么是热更新

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

大致的流程是,客户端在启动后访问更新的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服务器,做一下练习。

时间: 2024-11-05 19:00:25

[Cocos2d-x]Lua 资源热更新的相关文章

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

原地址:http://blog.csdn.net/dingxiaowei2013/article/details/20079683 我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略.注意哦,只是资源哦.关于代码的更新,我们稍后再来研究.理论上这个方案可以使用各种静态资源的更新,不仅仅是assetbundle打包的. (转载请注明原文地址http://blog.csdn.net/janeky/article/details/17666409) 原理 现在的手游

【Cocos2d-x】实现资源热更新

热更新介绍 什么是热更新? 游戏客户端启动时,主动请求服务端检查版本号,并更新资源到本地. 应用场景: 情况一:游戏客户端已经发布了,但突然发现有个比较严重的bug需要修复.这时需要更新游戏的代码(Lua代码). 情况二:情人节到了,需要搞个活动,在游戏中营造一个节日氛围.这时,需要更新游戏资源或增加一些功能. 好处:不需要重新打包和提交应用到市场等待审核. 热更新流程 AssetsManager 在Cocos2d-x中已经封装了用于实现热更新功能的类,就是AssetsManager. api说

Unity手游之路&lt;十二&gt;手游资源热更新策略探讨

http://blog.csdn.net/janeky/article/details/17666409 上一次我们学习了如何将资源进行打包.这次就可以用上场了,我们来探讨一下手游资源的增量更新策略.注意哦,只是资源哦.关于代码的更新,我们稍后再来研究.理论上这个方案可以使用各种静态资源的更新,不仅仅是assetbundle打包的. (转载请注明原文地址http://blog.csdn.net/janeky/article/details/17666409) 原理 现在的手游安装有几种方式.一种

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

简介 一个简单的关于页面,有一个图片,版本号,App名称等,着重演示各个系列的文章完整集成示例. 动机与意义 这是系列文章的最后一篇.今天抽空写下,收下尾.文章本身会在第四篇的基础上,简单扩充下代码,实现在线下载与重置更改的功能. 如果能较为仔细地阅读前四篇文章,第五篇给出的示例,应当是可以理解为无足轻重的.但是,大多数时候,我们更多的可能只是需要一个简易的解决方案,就是那种拿来就可以用的东西,那种我们需要先能看到一个简要的示例来看下效果再解决是否再继续阅读的方案.如此,对于很久以后,由于各种原

cocos2dx 3.1.1 在线热更新 自动更新(使用AssetsManager更新游戏资源包)

为什么要在线更新资源和脚本文件? 简单概括,如果你的游戏项目已经在google play 或Apple Store 等平台上架了,那么当你项目需要做一些活动或者修改前端的一些代码等那么你需要重新提交一个新版本给平台.但是平台审核和具体的上架时间是个不确定的.具体什么时候能上架,主要由具体的平台决定. 如果游戏项目是使用脚本语言进行编写的(如lua.js),那么一旦需要更新,则可以通过从服务器下载最新的脚本和资源,从而跳过平台直接实现在线更新.(有些平台是禁止在线更新资源方式的,但是你懂得) 闲话

Unity3D游戏开发之Lua与游戏的不解之缘终结篇:UniLua热更新完全解读

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei. 转载请注明出处,本文作者:

【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源热更新 Android热更新开源项目Tinker源码解析系类之三:so热更新 转载请标明本文来源:http://www.cnblogs

Unity官方公布热更新方案性能对比

孙广东  2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda ?  什么是热更新 ?  为何要热更新 ?  如何在iOS 上对Unity 应用进行热更新 ?  支持Unity iOS 热更新的各种Lua 插件的对比 什么是热更新 ? 广义定义 ? 无需关闭服务器,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码. ? 狭义定义( iOS热更新) ? 无需将代码重新打包提交至AppStore,即可更新客户端的执行代码,即

Unity官方发布热更新方案性能对照

孙广东  2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda ?  什么是热更新 ?  为何要热更新 ?  怎样在iOS 上对Unity 应用进行热更新 ?  支持Unity iOS 热更新的各种Lua 插件的对照 什么是热更新 ? 广义定义 ? 无需关闭server,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码. ? 狭义定义( iOS热更新) ? 无需将代码又一次打包提交至AppStore,就可以更新clien