zoukankan      html  css  js  c++  java
  • 【Cocos2dx3.x Lua】图片异步加载

    一、说明

        异步加载就是把消耗程序时间比较大的加载操作放到其他线程中,待加载完毕后通过回调函数的方式通知主线程。
     
    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中
     
     
  • 相关阅读:
    poj 1113 Wall 凸包的应用
    NYOJ 78 圈水池 (入门级凸包)
    Monotone Chain Convex Hull(单调链凸包)
    poj Sudoku(数独) DFS
    poj 3009 Curling 2.0(dfs)
    poj 3083 Children of the Candy Corn
    Python join()方法
    通过FISH和下一代测序检测肺腺癌ALK基因融合比较
    华大病原微生物检测
    NGS检测ALK融合大起底--转载
  • 原文地址:https://www.cnblogs.com/luosongchao/p/4337933.html
Copyright © 2011-2022 走看看