http://blog.csdn.net/w20175357/article/details/23546985
1、先說說addImageAsync()異步加載圖片的問題
做游戲的時候現在資源的比較大,所有我們必然會有一個loading界面,而我在找寫loading界面的方法的時候,發現了2種方法。
一種是自己創建一個線程,再在這個線程里面加載資源,不過由於openGL的限制,只能在主線程里面繪制UI,不過有的人也想出了其他的方法,就是先只緩存,再在主線程里面繪制。這里有這方面的教程。不過這種方法有點繞,反正我是搞得不是很清楚。
另一種,也是TestCpp里面使用的方法,那就是用
CCTextureCache::sharedTextureCache()->addImageAsync("Texture2D_Test3.png", this, callfuncO_selector(LoadingScene::loadingCallBack));
函數異步加載圖片,基本應用可以看TestCpp里面的TextureCacheTest這一個。
2、我遇到的問題
TestCpp里面當資源都加載好了的時候,它並沒有跳轉場景,而是把先前的畫面顯示的都移除,再添加新的精靈,但是我現在想做是當資源都加載好的時候就從loading界面跳轉到讀取成功界面,而不是簡單的把資源移除與添加新的資源。TextureCacheTest里面的寫法如下。詳細的請自行去TestCpp里面查看。
if (m_nNumberOfLoadedSprites == m_nNumberOfSprites) { this->removeChild(m_pLabelLoading, true); this->removeChild(m_pLabelPercent, true); addSprite(); //僅僅添加精靈 }
但是我想做的是
if (m_nLoadedResources == m_nAllLoadResources) { this->removeAllChildren(); CCScene *loginSuccessScene = LoginSuccessScene::scene(); CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.1f, loginSuccessScene)); }
不過當我這么寫的時候就遇到了問題,那就是場景確實是跳轉了,但是只是一閃而逝,就又跳回到了loading的場景里面,而由於我this->removeAllChildren(),所以最后屏幕就黑了。
3、我的解決方法
關於上面那個問題,我的理解是由於我是在addImageAsync的回調函數LoadingScene::loadingCallBack 里面寫的跳轉場景,但是當這個線程執行完了之后,主線程會還是在執行的。所以這個里面的跳轉只是一閃而逝的。然后我請教他人知道了其實主線程里面有一個update()函數,它會一直調用。於是我便把上面的那個函數寫在了update里面,因為update是引擎自帶的函數,所以雖然我顯性沒有調用,但是它會自行調用,你可以直接查看update()函數的原型。update()如下
void LoadingScene::update( float delta ) { if (m_nLoadedResources == m_nAllLoadResources) { this->removeAllChildren(); CCScene *loginSuccessScene = LoginSuccessScene::scene(); CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.1f, loginSuccessScene)); } }
但是這樣其實會有一個問題,當資源讀取很快的時候,會跳到loading成功界面,不過之后還是會閃一下,我的理解是當跳轉的時候,可能異步加載資源海沒有完全完成,所以還是會運行那個函數。所以我便加了一個變量m_fWaitTime,在update里面讓其m_fWaitTime += delta; 並當m_fWaitTime > 5.0f的時候才跳轉頁面,當你想測試一個不等待的時候的效果的時候可以將這個變量相關的東西都注釋掉,當然了,我們運行游戲的時候加載時間一般都相對較長,所以不用擔心。(不過我還沒有真機測試過=.=,如果真機測試的時候出問題了,我會過來及時更正的)。
4、loading源代碼
下面是loading的主要代碼,其中addImageAsync()加載的資源都可以用CCTexture2D *texture1 = CCTextureCache::sharedTextureCache()->textureForKey("Test.png");直接取的並使用,就算是在不同的類里面使用而是同一個類。
LoadingScene.h
#ifndef _LOADING_SCENE_H__ #define _LOADING_SCENE_H__ #include "cocos2d.h" USING_NS_CC; class LoadingScene : public CCLayer { public: virtual bool init(); static CCScene *scene(); void loadSuccess(); //讀取的回調函數 void loadingCallBack(CCObject *obj); void addSprite(); void update(float delta); void updateProgress(float dt); CREATE_FUNC(LoadingScene); private: //讀取開始時候的進度條 CCSprite *m_pLoadBarStart; //讀取完成時候的進度條 CCProgressTimer *m_pLoadBarEnd; //線程相關的函數 //總的加載圖片數 int m_nAllLoadResources; //當前加載圖片數 int m_nLoadedResources; //讀取進度 float m_fProgressIndex; CCLabelTTF *m_pLabelLoading; CCLabelTTF *m_pLabelPercent; // 當要測試有m_fWaitTime的效果的時候,將下一行與update()和init()里面初始化的注釋取消掉即可 // float m_fWaitTime; }; #endif
LoadingScene.cpp
#include "LoadingScene.h" #include "LoginSuccessScene.h" #include "Global.h" CCScene* LoadingScene::scene() { CCScene * scene = NULL; do { // 'scene' is an autorelease object scene = CCScene::create(); CC_BREAK_IF(! scene); // 'layer' is an autorelease object LoadingScene *layer = LoadingScene::create(); CC_BREAK_IF(! layer); // add layer as a child to scene scene->addChild(layer); } while (0); // return the scene return scene; } bool LoadingScene::init() { if (!CCLayer::init()) { return false; } scheduleUpdate(); CCSize size = CCDirector::sharedDirector()->getWinSize(); m_nAllLoadResources = 3; m_nLoadedResources = 0; m_fProgressIndex = 0.0; // m_fWaitTime = 0; m_pLabelLoading = CCLabelTTF::create("loading...", "Arial", 15); m_pLabelPercent = CCLabelTTF::create("%0", "Arial", 15); m_pLabelLoading->setPosition(ccp(400, 200)); m_pLabelPercent->setPosition(ccp(450, 200)); this->addChild(m_pLabelLoading, 1); this->addChild(m_pLabelPercent, 1); //loading的動畫效果 m_pLoadBarStart = CCSprite::create("loadingStart.jpg"); m_pLoadBarStart->setPosition(ccp(size.width / 2, size.height * 3 / 4)); m_pLoadBarStart->setScale(2.0f); this->addChild(m_pLoadBarStart); m_pLoadBarEnd = CCProgressTimer::create(CCSprite::create("loadingEnd.jpg")); m_pLoadBarEnd->setPercentage(1.0f); m_pLoadBarEnd->setPosition(ccp(size.width / 2, size.height * 3 / 4)); m_pLoadBarEnd->setType(kCCProgressTimerTypeBar); m_pLoadBarEnd->setBarChangeRate(ccp(1, 0)); m_pLoadBarEnd->setMidpoint(ccp(0, 0)); m_pLoadBarEnd->setScale(2.0f); this->addChild(m_pLoadBarEnd); //讀取資源 CCTextureCache::sharedTextureCache()->addImageAsync("Texture2D_Test1.png", this, callfuncO_selector(LoadingScene::loadingCallBack)); CCTextureCache::sharedTextureCache()->addImageAsync("Texture2D_Test2.png", this, callfuncO_selector(LoadingScene::loadingCallBack)); CCTextureCache::sharedTextureCache()->addImageAsync("Texture2D_Test3.png", this, callfuncO_selector(LoadingScene::loadingCallBack)); //設置一個動作,令進度條2秒內讀取到100% // CCProgressTo *action = CCProgressTo::create(2, 100); // m_pLoadBarEnd->runAction(CCSequence::create(action, CCCallFunc::create(this, // callfunc_selector(LoadingScene::loadSuccess)), NULL)); return true; } void LoadingScene::loadSuccess() { this->removeAllChildren(); CCScene *loginSuccessScene = LoginSuccessScene::scene(); CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(0.1f, loginSuccessScene)); // CCDirector::sharedDirector()->pushScene(loginSuccessScene); } void LoadingScene::loadingCallBack(CCObject *obj) { ++m_nLoadedResources; char tmp[10]; sprintf(tmp,"%%%d", (int)(((float)m_nLoadedResources / m_nAllLoadResources ) * 100)); m_pLabelPercent->setString(tmp); m_fProgressIndex = (((float)m_nLoadedResources / m_nAllLoadResources ) * 100); m_pLoadBarEnd->setPercentage(m_fProgressIndex); } void LoadingScene::update( float delta ) { // m_fWaitTime += delta; if (m_nLoadedResources == m_nAllLoadResources // && m_fWaitTime > 5.0f ) { loadSuccess(); } }
如果有什么錯誤或者解釋不當的地方歡迎指正,我只是因為這個困擾了我的問題得到了解決便寫上來,讓也被這個問題困擾的人能夠得到解答。希望能夠幫到你們。