Cocos2d-x3.2 TextureCache类异步加载功能讲解

本文TextureCache类异步加载功能的代码抽出,总共代码就200多行,感兴趣可以看看。

研究这个主要是因为项目中需要异步插入数据,但之前的方法在Android上总是崩溃所以想到TextureCache有异步加载的功能就将其抽出了。

原文地址:http://blog.csdn.net/qqmcy/article/details/39890837

代码下载:http://download.csdn.net/detail/qqmcy/8011589


首先,创建AsyncTaskTime类,主要模拟一个费时的方法

AsyncTaskTime.h

#include "cocos2d.h"

USING_NS_CC;

class AsyncTaskTime
{
public:
    
    //模拟一个费时操作
    bool initWithImageFileThreadSafe(const std::string &filename);
    
    
};

AsyncTaskTime.cpp

//
//  AsyncTaskTime.cpp
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#include "AsyncTaskTime.h"

bool AsyncTaskTime::initWithImageFileThreadSafe(const std::string &filename)
{
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    return true;
}

创建异步加载功能类

AsyncTest.h

//
//  AsyncTest.h
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#ifndef __cpp4__AsyncTest__
#define __cpp4__AsyncTest__

#include "cocos2d.h"
#include "AsyncTaskTime.h"

using namespace std;

USING_NS_CC;
class AsyncTest : public Ref
{
public:
    CREATE_FUNC(AsyncTest);
    
    virtual bool init();
    
    AsyncTest();
    
    // 异步加载
    void addImageAsync(const string &path,const function<void(AsyncTaskTime *)> &callback);
private:
    
    void addImageAsyncCallback(float dt);
    //加载数据
    void loadImage();
    
public:
    struct AsyncStruct
    {
    public:
        AsyncStruct(const string &fn,function<void(AsyncTaskTime *)> f): filename(fn),callback(f){};
        
        string filename;
        function<void(AsyncTaskTime *)> callback;
    };
    
protected:
    
    typedef struct
    {
        AsyncStruct *asyncStruct;
        AsyncTaskTime *image;
    }ImageInfo;
    
    
    thread *_loadingThread;
    queue<AsyncStruct *>        *_asyncStructQueue;
    deque<ImageInfo *>          *_ImageInfoQueue;
    
    mutex                       _asyncStructQueueMutex;
    mutex                       _imageInfoMutex;
    
    mutex                       _sleepMutex;
    condition_variable          _sleepCondition;
    
    bool                        _needQuit;
    int                         _asyncRefCount;
    unordered_map<std::string,AsyncTaskTime* > _textures;
    
    
    
    
};

#endif /* defined(__cpp4__AsyncTest__) */

AsyncTest.cpp

//
//  AsyncTest.cpp
//  cpp4
//
//  Created by 杜甲 on 10/8/14.
//
//

#include "AsyncTest.h"

AsyncTest::AsyncTest()
: _loadingThread(nullptr),_asyncStructQueue(nullptr),_ImageInfoQueue(nullptr),_needQuit(false),_asyncRefCount(0)
{
    
}

bool AsyncTest::init()
{
    return true;
}

void AsyncTest::addImageAsync(const string &path,const function<void (AsyncTaskTime *)> &callback)
{
    AsyncTaskTime *texture = nullptr;
    
    auto it = _textures.find(path);
    if (it != _textures.end()) {
        texture = it->second;
    }
    
    if (texture != nullptr) {
        callback(texture);
        return;
    }
    
    if (_asyncStructQueue == nullptr) {
        _asyncStructQueue = new queue<AsyncStruct *>();
        _ImageInfoQueue = new deque<ImageInfo *>();
        
        _loadingThread = new thread(&AsyncTest::loadImage,this);
        
        _needQuit = false;
    }
    
    if (0 == _asyncRefCount) {
        Director::getInstance()->getScheduler()->schedule(schedule_selector(AsyncTest::addImageAsyncCallback),this,false);
    }
    
    ++_asyncRefCount;
    
    auto data = new AsyncStruct(path,callback);
    
    _asyncStructQueueMutex.lock();
    _asyncStructQueue->push(data);
    _asyncStructQueueMutex.unlock();
    
    _sleepCondition.notify_one(); //将等待 condition_variable 对象的其中一个线程解除阻塞。
    
    
    
}

void AsyncTest::loadImage()
{
    AsyncStruct *asyncStruct = nullptr;
    while (true) {
        queue<AsyncStruct *> *pQueue = _asyncStructQueue;
        _asyncStructQueueMutex.lock();
        if (pQueue->empty()) {
            
        }
        else{
            asyncStruct = pQueue->front();
            pQueue->pop();
            _asyncStructQueueMutex.unlock();
        }
        
        AsyncTaskTime *image = nullptr;
        bool generateImage = false;
        
        auto it = _textures.find(asyncStruct->filename);
        if (it == _textures.end()) {
            _imageInfoMutex.lock();
            ImageInfo *imageInfo;
            size_t pos = 0;
            size_t infoSize = _ImageInfoQueue->size();
            for (; pos < infoSize; pos++) {
                imageInfo = (*_ImageInfoQueue)[pos];
                if (imageInfo->asyncStruct->filename.compare(asyncStruct->filename) == 0)
                    break;
                
            }
            _imageInfoMutex.unlock();
            if (infoSize == 0 || pos == infoSize)
                generateImage = true;
            
        }
        
        if (generateImage) {
            const string &filename = asyncStruct->filename;
            image = new AsyncTaskTime();
            if (image && !image->initWithImageFileThreadSafe(filename)) {
                continue;
            }
        }
        
        auto imageInfo = new ImageInfo();
        imageInfo->asyncStruct = asyncStruct;
        imageInfo->image = image;
        
        _imageInfoMutex.lock();
        _ImageInfoQueue->push_back(imageInfo);
        _imageInfoMutex.unlock();
        
    }
    
    if (_asyncStructQueue != nullptr) {
        delete _asyncStructQueue;
        _asyncStructQueue = nullptr;
        delete _ImageInfoQueue;
        _ImageInfoQueue = nullptr;
    }
    
}

void AsyncTest::addImageAsyncCallback(float dt)
{
    deque<ImageInfo *> *imagesQueue = _ImageInfoQueue;
    _imageInfoMutex.lock();
    if (imagesQueue->empty()) {
        _imageInfoMutex.unlock();
    }
    else{
        auto imageInfo = imagesQueue->front();
        imagesQueue->pop_front();
        _imageInfoMutex.unlock();
        
        auto asyncStruct = imageInfo->asyncStruct;
        auto image = imageInfo->image;
        if (asyncStruct->callback) {
            asyncStruct->callback(image);
        }
        
        --_asyncRefCount;
        if (0 == _asyncRefCount) {
            Director::getInstance()->getScheduler()->unschedule(schedule_selector(AsyncTest::addImageAsyncCallback),this);
        }
    }
}




调用:

HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "AsyncTest.h"
USING_NS_CC;


class HelloWorld : public cocos2d::Layer
{
public:
    // Here's a difference. Method 'init' in cocos2d-x returns bool,instead of returning 'id' in cocos2d-iphone
    
    HelloWorld();
    
    virtual bool init();  

    // there's no 'id' in cpp,so we recommend returning the class instance pointer
    static cocos2d::Scene* scene();
    
   
    
    // implement the "static node()" method manually
    CREATE_FUNC(HelloWorld);
    
    
private:
    Size winSize;
    //这里添加一个回调方法
    void loadCallback1(AsyncTaskTime *time);
    
};

#endif // __HELLOWORLD_SCENE_H__

HelloWorldScene.cpp

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }
    
    auto as = AsyncTest::create();
    as->retain();
    as->addImageAsync("test",CC_CALLBACK_1(HelloWorld::loadCallback1,this));
    
    
    
       
    return true;
}

void HelloWorld::loadCallback1(AsyncTaskTime *time)
{
    
    log("加载完成");
    
}


控制台:

cocos2d: 加载完成


这样我们就将TextureCache中

virtual void addImageAsync(conststd::string &filepath,const std::function<void(Texture2D*)>& callback);

这个异步加载数据的功能实现了。

相关文章

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