码迷,mamicode.com
首页 > 其他好文 > 详细

【Cocos2dx3.x Lua】图片异步加载

时间:2015-03-14 18:11:58      阅读:231      评论:0      收藏:0      [点我收藏+]

标签:

一、说明

    异步加载就是把消耗程序时间比较大的加载操作放到其他线程中,待加载完毕后通过回调函数的方式通知主线程。
 
addImageAsync函数实现(Cocos2dx 3.3)

Link: http://codepad.org/UuNcXMqq    [ raw code | fork ]  
 
void TextureCache::addImageAsync(const std::string &path, const std::function<void(Texture2D*)>& callback)
{
    Texture2D *texture = nullptr;

    std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path);

    auto it = _textures.find(fullpath);
    if( it != _textures.end() )
        texture = it->second;

    if (texture != nullptr)
    {
        callback(texture);
        return;
    }

    // lazy init
    if (_asyncStructQueue == nullptr)
    {             
        _asyncStructQueue = new queue<AsyncStruct*>();
        _imageInfoQueue   = new deque<ImageInfo*>();        

        // create a new thread to load images
        _loadingThread = new std::thread(&TextureCache::loadImage, this);

        _needQuit = false;
    }

    if (0 == _asyncRefCount)
    {
        Director::getInstance()->getScheduler()->schedule(CC_SCHEDULE_SELECTOR(TextureCache::addImageAsyncCallBack), this, 0, false);
    }

    ++_asyncRefCount;

    // generate async struct
    AsyncStruct *data = new (std::nothrow) AsyncStruct(fullpath, callback);

    // add async struct into queue
    _asyncStructQueueMutex.lock();
    _asyncStructQueue->push(data);
    _asyncStructQueueMutex.unlock();

    _sleepCondition.notify_one();
}

 

异步加载实例:
    ImageAsync.lua
    

Link: http://codepad.org/ydr3m4bK    [ raw code | fork ]  
--图片异步加载
ImageAsync=class("ImageAsync",function()
    return cc.Layer:create()
end)

ImageAsync.ctor=function(self)
    self.size=cc.Director:getInstance():getWinSize()
    self:initTexture()
    self:loadingLabel()
    self.curIndex=0 --当前loaded的图片编号

    self:registerScriptHandler(function(tag)
        if tag=="enter" then
            --设置定时器
            self:scheduleUpdateWithPriorityLua(function(dt)
                self:loadTexture()
            end,0)
        elseif tag=="exit" then
            cclog("exit")
            self:unscheduleUpdate()
            cc.Director:getInstance():getTextureCache():removeAllTextures()
        end
    end)
end

--初始化loadding label
ImageAsync.loadingLabel=function(self)
    local label=cc.Label:createWithTTF("Loading...0%", "res/fonts/arial.ttf", 32)
    label:setPosition(self.size.width/2,self.size.height/4)
    self:addChild(label)
    self.label=label
end

--初始化图片集
ImageAsync.initTexture=function(self)
    self.textures={}
    for i=0,7 do
        for j=0,7 do
            local image=string.format("Images/sprites_test/sprite-%d-%d.png",i,j)
            table.insert(self.textures,image)
        end
    end
end

--异步加载图片
ImageAsync.loadTexture=function(self)
    local function loadedImage(texture)
        local sprite=cc.Sprite:createWithTexture(texture)
        sprite:setPosition(cc.p(self.size.width/2,self.size.height/2))
        sprite:setScale(2)
        self:addChild(sprite)
        self.curIndex=self.curIndex+1
        self.label:setString(string.format("Loading...%d%%",math.floor(100*self.curIndex/#self.textures)))
        cclog(string.format("loaded self.textures[%d]:%s",self.curIndex,self.textures[self.curIndex]))
    end

    local textureCache=cc.Director:getInstance():getTextureCache()
    for i=1,#self.textures do
        textureCache:addImageAsync(self.textures[i],loadedImage)
    end

    self:unscheduleUpdate()
end

ImageAsync.create=function()
    local layer=ImageAsync.new()
    return layer
end

return ImageAsync

 

执行效果:
    技术分享
 
补充说明:
    Cocos2dx TextureCache会加载图片到内存中,创建Sprite  initWithFile时如果内存中已经有该texture直接使用该texture,这样就达到了减少切换界面时出现的卡顿(直接从内存中取资源,而非IO操作),具体实现如下:
    技术分享
 
TextureCache的addImage实现如下:
Texture2D * TextureCache::addImage(const std::string &path)
{
    Texture2D * texture = nullptr;
    Image* image = nullptr;
    // Split up directory and filename
    // MUTEX:
    // Needed since addImageAsync calls this method from a different thread

    std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path);
    if (fullpath.size() == 0)
    {
        return nullptr;
    }
    auto it = _textures.find(fullpath);
    if( it != _textures.end() )
        texture = it->second;

    if (! texture)
    {
        // all images are handled by UIImage except PVR extension that is handled by our own handler
        do 
        {
            image = new (std::nothrow) Image();
            CC_BREAK_IF(nullptr == image);

            bool bRet = image->initWithImageFile(fullpath);
            CC_BREAK_IF(!bRet);

            texture = new (std::nothrow) Texture2D();

            if( texture && texture->initWithImage(image) )
            {
#if CC_ENABLE_CACHE_TEXTURE_DATA
                // cache the texture file name
                VolatileTextureMgr::addImageTexture(texture, fullpath);
#endif
                // texture already retained, no need to re-retain it
                _textures.insert( std::make_pair(fullpath, texture) );
            }
            else
            {
                CCLOG("cocos2d: Couldn‘t create texture for file:%s in TextureCache", path.c_str());
            }
        } while (0);
    }

    CC_SAFE_RELEASE(image);

    return texture;
}
 
补充说明:
    异步加载plist和png图片——方法是在异步加载png图片的回调函数中,加载plist文件
    Link: http://codepad.org/BuWR4Hdl    [ raw code | fork ]
 
local BaseLoading=class("BaseLoading",function()
    return cc.Layer:create()
end)

BaseLoading.init=function(self)
    self._size=cc.Director:getInstance():getWinSize()
    self._textures={}
    self._curIndex=1 --当前loaded的图片编号

    self:initTexture()
    self:loadingUI()
end

--需要加载的所有资源文件
BaseLoading.initTexture=function(self)

end

--异步加载图片
BaseLoading.loadTexture=function(self)
    local frameCache=cc.SpriteFrameCache:getInstance()
    --加载图片
    local function loadPng(texture)
        self._label:setString(string.format("Loading...%d%%",math.floor(100*self._curIndex/#self._textures)))
        cclog(string.format("loaded self.textures[%d]:%s",self._curIndex,self._textures[self._curIndex].loc..".png"))
        if self._curIndex==#self._textures then
            self:finishLoading()
        end
        self._curIndex=self._curIndex+1
    end


    --加载Plist图片
    local function loadPlist(texture)
        frameCache:addSpriteFrames(self._textures[self._curIndex].loc..".plist")
        self._label:setString(string.format("Loading...%d%%",math.floor(100*self._curIndex/#self._textures)))
        cclog(string.format("loaded self.textures[%d]:%s",self._curIndex,self._textures[self._curIndex].loc..".png"))
        if self._curIndex==#self._textures then
            self:finishLoading()
        end
        self._curIndex=self._curIndex+1
    end

    local textureCache=cc.Director:getInstance():getTextureCache()
    for i=1,#self._textures do
        local rtype=self._textures[i].rtype
        if rtype=="png" then
            textureCache:addImageAsync(self._textures[i].loc..".png",loadPng)
        elseif rtype=="plist" then
            textureCache:addImageAsync(self._textures[i].loc..".png",loadPlist)
        end
    end
    self:unscheduleUpdate()
end

--loading UI
BaseLoading.loadingUI=function(self)
    local label=cc.Label:createWithTTF("Loading...0%", "res/fonts/Marker Felt.ttf", 32)
    label:setPosition(self._size.width/2,self._size.height/4)
    self:addChild(label)
    self._label=label
end


BaseLoading.startLoading=function(self)
    self:registerScriptHandler(function(tag)
        if tag=="enter" then
            --设置定时器
            self:scheduleUpdateWithPriorityLua(function(dt)
                self:loadTexture()
            end,0)
        elseif tag=="exit" then
            self:unscheduleUpdate()
        end
    end)
end

--完成异步加载图片回调函数
BaseLoading.finishLoading=function(self)

end

return BaseLoading
补充说明:
    异步加载plist纹理和png图片
    加载plist时,先加载plist对应的png图片,加载plist对应的png图片之后,在异步回调函数中,将plist载入textureCache中
 
 

【Cocos2dx3.x Lua】图片异步加载

标签:

原文地址:http://www.cnblogs.com/luosongchao/p/4337933.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!