首先说明一个问题:

为什么要在线更新资源和脚本文件!?

对于此问题,那要说的太多了,简单概括,如果你的项目已经在google play 或Apple Store 等平台上架了,那么当你项目需要做一些活动或者修改前端的一些代码等那么你需要重新提交一个新版本给平台,这时候你的上架时候是个不确定的时候,具体什么时候能上架,主要跟平台有关,你再着急,也没有用的。

那么如果你的项目是使用脚本语言进行编写的,例如lua,js等等,那么一旦你有需要更新你的项目,你完全可以通过从服务器下载最新的脚本和资源来实现在线更新,免去很多烦恼,至少更新再也不需要平台的审核来限制了不是么~(有些平台是禁止在线更新资源方式的,但是你懂得)

那么如何在项目中实现在线更新呢?则是本章具体需要跟大家分享的教程啦。

(有童鞋问我,单机怎么办? 一般自己搭个服务器,专用于在线更新。不过一般单机不这么做,这套下载更新主要用于网游 )

下面进入本章的重要内容:

在cocos2dx 2.x 引擎的扩展包(extensions)中有一个AssetsManager

AssetsManager 主要功能就是下载资源到本地,并帮你解压!

如果大家还不知道这个类,那么可以先到cocos2dx引擎的http:///Users/slater/Documents/cocos2d-2.1rc0-x-2.1.2-hotfix/samples/Cpp/AssetsManagerTest 目录下运行示例。

(注:当前Himi使用的是cocos2dx-2.1.2hotfix版本这个示例在我的mac os无法正常运行)

下面Himi新建个项目来详细讲解AssetsManager:

Himi这里拿lua项目进行,首先创建一个新的cocos2dx-lua 的项目:

第一步:将项目中Resoures目录下的hello.lua 删除!

第二步:在AppDelegate.h 中添加如下代码:

先导入所需的头文件:

1
2
3
4
5
6
7
8
9
10
11
#include "cocos2d.h"
#include "AssetsManager.h"
#include "cocos-ext.h"
using namespace std;
using namespace cocos2d;
using namespace extension;
#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
#include <dirent.h>
#include <sys/stat.h>
#endif

继续添加变量和方法名:

1
2
3
void updateFiles();
void createDownDir();
string pathToSave;

pathToSave 变量用于保存下载的路径!用于添加到 ccluaEngine 引擎中,这样便于ccluaEngine查找Lua文件!

第三步:在AppDelegate.cpp 中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
static AssetsManager* pAssetsManager;
void AppDelegate::updateFiles(){
createDownDir();
pAssetsManager = new AssetsManager( "https://raw.github.com/HimiGame/himigame/master/hello.zip" , "https://raw.github.com/HimiGame/himigame/master/version" );
if (pAssetsManager->checkUpdate()){
if ( pAssetsManager->update() ){ //改源码
ccluaEngine* pEngine = ccluaEngine::defaultEngine();
ccScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
//首先添加下载文件的目录
pEngine->addSearchPath(pathToSave.c_str());
//继续添加本地hello2的路径到ccluaEngine中
string path = CCFileUtils::sharedFileUtils()->fullPathForFilename( "hello2.lua" );
pEngine->addSearchPath(path.substr(0,path.find_last_of( "/" )).c_str());
//运行下载文件hello.lua
string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename( "hello.lua" );
pEngine->executeScriptFile(runLua.c_str());
}
}
}
void AppDelegate::createDownDir(){
pathToSave = CCFileUtils::sharedFileUtils()->getWritablePath();
pathToSave += "Himi" ;
// Create the folder if it doesn't exist
#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 ((GetFileAttributesA(pathToSave.c_str())) == INVALID_FILE_ATTRIBUTES)
{
CreateDirectoryA(pathToSave.c_str(),0);
}
#endif
}

首先介绍createDwomDir函数:

(注:所有连接都是Hmi在GitHub服务器中的,大家可以所以访问)!

此函数主要用于在项目目录下新建一个文件夹,到底创建到哪里,你不用管,交给如下函数:

CCFileUtils::sharedFileUtils()->getWritablePath();

上面这个函数能从ios、android平台自动找到可写入的路径!

createDwomDir 函数中 pathToSave += “Himi”; 主要作用是在getWritablePath()路径后自定义一个目录名!需要不需要都可以的,如果想创建个,那就自定义即可,名字无所谓思密达。

继续介绍 updateFiles 函数

此函数中,首先我们调用createDwomDir 函数用于创建我们新的写入目录,并且将目录保存到pathToSave变量中。

然后我们创建了一个AssetsManager 实例,这里要静态。AssetsManager创建函数有两种,如下:

1
2
3
1. AssetsManager::AssetsManager( const char * packageUrl, const char * versionFileUrl)
2. AssetsManager::AssetsManager( const char * packageUrl, const char * versionFileUrl, const char * storagePath)

首先看第一种创建函数:

参数1 : packgeUrl: 表示需要下载更新的zip包的URL地址

参数2 : versionFileUrl :表示获取当前服务器版本号的rul,用于匹配客户端是否需要更新!

第二种创建方式多了一个参数: storagePath 表示我们的自定义包名,如createDwomDir函数中的pathToSave += “Himi” 一句功能一样。

而在AssetsManager类中封装了很多方法,例如检查是否需要更新、更新下载文件、获取packageUrl等。具体方法可看AssetsManager源码!

pAssetsManager->checkUpdate() :通过得到服务器返回的版本号与本地版本号进行匹配如不一致则返回true,反之返回false。

(注:大家可以通过版本号对比,做其他功能,比如更新提示等)

一旦通过判断checkUpdate函数返回true,我们即可调用AssetsManager中的update进行文件更新!

这里要注意:由于当前AssetsManager的源码中并没有给予我们判断文件下载成功的函数!因此Himi与AssetsManager作者联系,我们可以更改update函数让其返回bool类型即可!

(注:update 函数中对版本、下载文件、解压、存储最新版本号等做了判断,因此当此函数返回true,则完成一切操作)

修改方式如下:首先我们到源码AssetsManager.h中将如下upate函数修改:

1
2
3
4
5
virtual void update();
修改成如下:
virtual bool update();

继续到AssetsManager.cpp 中update函数进行修改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
修改为:
bool AssetsManager::update()
{
// 1. Urls of package and version should be valid;
// 2. Package should be a zip file.
if (_versionFileUrl.size() == 0 ||
_packageUrl.size() == 0 ||
std::string::npos == _packageUrl.find( ".zip" ))
{
cclOG( "no version file url,or no package url,or the package is not a zip file" );
return false ;
}
// Check if there is a new version.
if (! checkUpdate()) return false ;
// Is package already downloaded?
string downloadedVersion = CCUserDefault::sharedUserDefault()->getStringForKey(KEY_OF_DOWNLOADED_VERSION);
if (downloadedVersion != _version)
{
if (! downLoad()) return false ;
// Record downloaded version.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION,_version.c_str());
CCUserDefault::sharedUserDefault()->flush();
}
// Uncompress zip file.
if (! uncompress()) return false ;
// Record new version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_VERSION,_version.c_str());
// Unrecord downloaded version code.
CCUserDefault::sharedUserDefault()->setStringForKey(KEY_OF_DOWNLOADED_VERSION, "" );
CCUserDefault::sharedUserDefault()->flush();
// Set resource search path.
setSearchPath();
// Delete unloaded zip file.
string zipfileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
if ( remove (zipfileName.c_str()) != 0)
{
cclOG( "can not remove downloaded zip file" );
}
return true ;
}

当我们做了如此的修改后,那么当文件下载完成后则会返回true!

最后我们来看如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
ccluaEngine* pEngine = ccluaEngine::defaultEngine();
ccScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
//首先添加下载文件的目录
pEngine->addSearchPath(pathToSave.c_str());
//继续添加本地hello2的路径到ccluaEngine中
string path = CCFileUtils::sharedFileUtils()->fullPathForFilename( "hello2.lua" );
pEngine->addSearchPath(path.substr(0,path.find_last_of( "/" )).c_str());
//运行下载文件hello.lua
string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename( "hello.lua" );
pEngine->executeScriptFile(runLua.c_str());

首先我们将文件更新下来的路径通过setScriptEngine添加到ccluaEngine中,然后将hello2.lua 的路径也添加到ccluaEngine的搜索途径中,这样一来ccluaEngine 会从我们设置的这两个路径中去找我们在lua中require的对应lua文件!这一步设置必须设置!因为ccluaEngine不像cocos2dx那样自动帮我们找文件路径!ccluaEngine 是不存在路径的,所以我们要手动设置ccluaEngine搜索路径,以便找到对应的lua文件!

也正是因为ccluaEngine不会自动帮我们找文件路径,因此我们运行lua脚本时,必须将运行的脚本lua文件完整的路径传入,如下:

1
2
3
//运行下载文件hello.lua
string runLua = CCFileUtils::sharedFileUtils()->fullPathForFilename( "hello.lua" );
pEngine->executeScriptFile(runLua.c_str());

下面我们开始书写测试代码:

在AppDelegate.cpp中的 applicationDidFinishLaunching 函数中注释一些代码并且添加测试代码,修改后的applicationDidFinishLaunching 函数内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bool AppDelegate::applicationDidFinishLaunching()
{
// initialize director
CCDirector *pDirector = CCDirector::sharedDirector();
pDirector->setopenGLView(CCEGLView::sharedOpenGLView());
// turn on display FPS
pDirector->setdisplayStats( true );
// set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / 60);
// register lua engine
// ccluaEngine* pEngine = ccluaEngine::defaultEngine();
// ccScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
//
//#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
// CCString* pstrFileContent = CCString::createWithContentsOfFile("hello.lua");
// if (pstrFileContent)
// {
// pEngine->executeString(pstrFileContent->getCString());
// }
//#else
// std::string path = CCFileUtils::sharedFileUtils()->fullPathForFilename("hello.lua");
// pEngine->addSearchPath(path.substr(0,path.find_last_of("/")).c_str());
// pEngine->executeScriptFile(path.c_str());
//#endif
//删除hello.lua
pathToSave= "" ;
updateFiles();
return true ;
}

下面开始运行!需要注意的是我们本地是完全不存在hello.lua文件的,所以一旦我们运行成功出现画面说明已经利用AssetsManager成功的在线下载了hello.lua文件!

运行截图如下:

从如上的运行截图中可以看出,首先我们得到服务器传来的版本号2.1.1,然后进行checkUpdate函数,此函数是从本地的存储文件找是否有版本号,如果没有那么就默认为可下载,如果有则会对比,如不一致则进行更新。

那么当文件完整下载下来之后update函数则自动会我们在本地保存最新从服务器拿到的版本号!紧接着update函数还为我们进行了对zip文件的解压,解压成功后会自动删除zip包!

因此如果大家运行过自己的这个项目成功下载运行了,那么下载运行请删除项目后再运行,因为第一次的成功运行已经将最新版本号记录保存下来了,你也可以通过修改服务器版本号或者删除项目的存储文件。

总结本文的教程:

第一: ccluaEngine 引擎是不会自动帮我们找文件的,所以你一旦有一个新的运行脚本的路径,一定要通过 ccluaEngine的addSearchPath函数告知!这样的话,当你的一个lua文件采用require其他脚本文件,ccluaEngine就会在你addSearchPath的路径中进行查找!

第二: 如果你想让自己项目自带的脚本与下载脚本同时使用,例如自己项目有a.lua 其中a.lua 中包含一句代码: requireb “b” ,而b.lua是你通过在线更新下载下来的。那么a.lua 和 b.lua的路径都要通过 addSearchPath 设置下各自的路径。

第三:lua engine应该也是支持搜索路径的优先级的,所以你可以通过控制pEngine->addSearchPath()的调用顺序,从而控制当你本地项目与下载更新同时拥有同一个名字的脚本等资源,可以优先选择使用哪个!

第四: 在AppStore 规定不允许在主游戏线程中进行联网,然后我们使用的AssetsManager的下载更新却是在联网下载,所以大家要使用异步来做!另外及时没有这条规定我想童鞋们也不会让联网放主游戏线程中吧!

第五:AssetsManager 中还有其他的功能,更多的功能请大家自己看cocos2dx引擎的示例项目!

最后给出Himi的示例项目下载地址:

OLUpdateFilesByHimi : http://vdisk.weibo.com/s/ycZU1

【COCOS2DX-LUA 脚本开发之十二】Hybrid模式-利用AssetsManager实现在线更新脚本文件lua、js、图片等资源免去平台审核周期的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. H5混合开发app如何升级的方法

    本篇文章主要介绍了H5混合开发app如何升级的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. HTML5适合的情人节礼物有纪念日期功能

    这篇文章主要介绍了HTML5适合的情人节礼物有纪念日期功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. ios – 比较两个版本号

    如何比较两个版本号字符串?例如:3.1.1和3.1.2.5.4现在我需要找出3.1.2.5.4是否高于3.1.1但我不知道如何做到这一点.有谁能够帮我?

  6. ios – 如何使用Objective C类中的多个参数调用Swift函数?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  7. ios – Swift:递归值类型

    我有一个结构,我想要一个结构类型的全局变量?这个例子本质上是我实际创建的结构的简化版本.但是,它会抛出错误:有没有办法解决这个问题?

  8. iOS App版本编号

    iTunesConnect开发人员指南PDF(第47页),关于iOS应用程序的版本号,请参阅以下内容:Usetypicalsoftwareversioningconventions(suchas“1.0″or“1.0.1”or“1.1”)没有关于应用版本号的确切格式的声明.我们可以使用版本号,例如“1.0.0.1”或“1.0.0.0.1”吗?解决方法我的建议是坚持使用1.x.x格式作为应用商店用途

  9. Swift疑点解决2

    关于Swift中的String类型,String是一个结构体类型包含字符串的unicode但是长度没法算,同样没有length方法。因为Nsstring是OC中的类型,但是苹果工程师做了很好的兼容。还有Swift里一下非常好的方法如varops3=ops.map{$0.description}

  10. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部