cocos2d-x多线程 创建texture on another thread is forbitten

最近在修改一个cocos2d的项目,要把它移植到cocos2d-x,原来的项目中用到了多线程,但是在cocos2d-x中的实现有点不太一样,在CSDN上找了一篇文章,有详细的代码示例:在新的线程中加载资源文件。原文地址:http://www.jb51.cc/article/p-mlwqtjmb-nb.html

文章是在windows系统下讲解的,在xcode中同样需要导入pThread类库。

简单线程开启方法如下代码所示:

文件

.h

#ifndef_LOADING_SCENE_H__
  1. #define_LOADING_SCENE_H__
  2. #include"cocos2d.h"
  3. #include"pthread/pthread.h"
  4. classLoadingScene:publiccocos2d::CCScene{
  5. public:
  6. virtualboolinit();
  7. CREATE_FUNC(LoadingScene);
  8. intstart();
  9. voidupdate(floatdt);
  10. private:
  11. pthread_tpid;
  12. staticvoid*updateInfo(void*args);//注意线程函数必须是静态的
  13. };



cpp文件
#include"LoadingScene.h"

  1. #include"pthread/pthread.h"
  2. usingnamespacecocos2d;
  3. boolLoadingScene::init(){
  4. this->scheduleUpdate();
  5. start();
  6. returntrue;
  7. }
  8. voidLoadingScene::update(floatdt){
  9. //可以在这里重绘UI
  10. }
  11. void*LoadingScene::updateInfo(void*args){
  12. //可以在这里加载资源
  13. returnNULL;
  14. }
  15. intLoadingScene::start(){
  16. pthread_create(&pid,NULL,updateInfo,NULL);//开启新线程
  17. return0;
  18. }




二加载Plist

我们可以在新开的线程中,加载资源,设置一个静态变量bool,在新线程中,当加载完所有资源后,设置bool值为真。在主线程中Update中,检测bool值,为假,可以重绘UI(例如,显示加载图片,或者模拟加载进度),为真,则加载目标场景。相关代码如下:

void*LoadingScene::updateInfo(void*args){
  1. CCSpriteFrameCache*cache=CCSpriteFrameCache::sharedSpriteFrameCache();
  2. cache->addSpriteFramesWithFile("BattleIcons.plist");
  3. cache->addSpriteFramesWithFile("ArcherAnim.plist");
  4. cache->addSpriteFramesWithFile("DeathReaperAnim.plist");
  5. loadComplete=true;//状态值设为真,表示加载完成
  6. returnNULL;
  7. }



成功加载且运行后,你会发现新场景中所有精灵都不显示(类似于黑屏了)。为什么呢?

因为我们在加载plist文件时,addSpriteFramesWithFile方法里会帮我们创建plist对应Png图的Texture2D,并将其加载进缓存中。可是这里就遇到了一个OpenGl规范的问题:不能在新开的线程中,创建texture,texture必须在主线程创建.通俗点,就是所有的openglapi都必须在主线程中调用;其它的操作,比如文件,内存,plist等,可以在新线程中做,这个不是cocos2d不支持,是opengl的标准,不管你是在android,还是windows上使用opengl,都是这个原理。

所以不能在新线程中创建Texture2D,导致纹理都不显示,那么该怎么办?让我们看看CCSpriteFrameCache源码,发现CCSpriteFrameCache::addSpriteFramesWithFile(constchar *pszPlist,CCTexture2D*pobTexture)方法,是可以传入Texture2D参数的。是的,我们找到了解决方法

相关代码如下:

intLoadingScene::start(){
  1. CCTexture2D*texture=CCTextureCache::sharedTextureCache()->addImage("BattleIcons.png");//在这里(主线程中)加载plist对应的Png图片进纹理缓存
  2. CCTexture2D*texture2=CCTextureCache::sharedTextureCache()->addImage("ArcherAnim.png");//以这种方法加载的纹理,其Key值就是文件path值,即例如
  3. texture2的key值就是ArcherAnim.png
  4. CCTexture2D*texture3=CCTextureCache::sharedTextureCache()->addImage("DeathReaperAnim.png");
  5. pthread_create(&pid,NULL);//开启新线程
  6. return0;
  7. }
  8. void*LoadingScene::updateInfo(void*args){
  9. CCSpriteFrameCache*cache=CCSpriteFrameCache::sharedSpriteFrameCache();
  10. CCTextureCache*teCache=CCTextureCache::sharedTextureCache();
  11. CCTexture2D*texture1=teCache->textureForKey("BattleIcons.png");//从纹理缓存中取出Texure2D,并将其当参数传入addSpriteFramesWithFile方法
  12. cache->addSpriteFramesWithFile("BattleIcons.plist",texture1);
  13. CCTexture2D*texture2=teCache->textureForKey("ArcherAnim.png");
  14. cache->addSpriteFramesWithFile("ArcherAnim.plist",texture2);
  15. CCTexture2D*texture3=teCache->textureForKey("DeathReaperAnim.png");
  16. cache->addSpriteFramesWithFile("DeathReaperAnim.plist",texture3);
  17. loadComplete=true;
  18. returnNULL;
  19. }



这样解决,就不违背OpenGl规范,没有在新线程中创建Texture2D。

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...