LoadingController

--local MainSceneConfig = require "res.scripts.configs.MainSceneConfig" -- 暂时添加一个临时配置文件
--require "res.scripts.scenes.MainScene"

-- 加载事件
OnLoadingStart         = "OnLoadingStart";
OnLoadingProcess     = "OnLoadingProcess";
OnLoadingEnd         = "OnLoadingEnd";

-- 加载类型
SOUNDTYPE = "sounds";
TEXTURETYPE = "textures";
ATLASTYPE = "atlas";
ANIMATIONTYPE = "animations";
EFFECTTYPE   = "effects";

-- 加载控制逻辑
local LoadingController = class("LoadingController", Behavior);

function LoadingController:ctor(sceneName)
    LoadingController.super.ctor(self);

    -- 定义成员变量
    self.progress = 0; -- 加载进度
    self.totalLoadingNum = 0; --加载总数数量
    self.curLoadingNum = 0;  -- 当前加载数量
    self.loadingConfig = ""; -- 资源配置文件

    self.log = nil;        -- 加载界面log    
    self.btmLabel = nil; --进度显示标签    
    self.uiLayout = nil; -- 加载界面布局
    self.uiLayer = nil; -- 加载界面层
    self.curScene = nil; -- 上一个场景
    self.nextScene = nil; -- 下一个场景
    self.config = res[sceneName];-- 配置文件
    self.curSceneName = sceneName; 

    self.isLoaded = false;

    -- 随机抽取一只怪物
    local animKeys = table.keys(res.animations);
    if #animKeys > 0 then
        local index = math.random(1, #animKeys);
        self.animName = tostring(animKeys[index]);
        self.loadingxml = res.animations[self.animName];
        self.loadingplist = string.gsub(self.loadingxml, ".xml", ".plist")
        self.loadingpng = string.gsub (self.loadingxml, ".xml", ".png")
    end
end

function LoadingController:run(  )
    self.curScene = SceneM.getRunningScene();
    self.nextScene = nil;

    -- 1.ui层
    self.uiLayer = ObjectFactory.newLayer();
    self.uiLayer:setColor(ccc3(0, 0, 0));

    -- 2.创建构成加载场景的元素
    self.btmLabel = ObjectFactory.newBMFontLabel({text = "Loading 0%", font = res.fonts.UIFont,})
    self.btmLabel:setPosition(ccp(Screen.cx, Screen.cy - 80));
    self.uiLayer:addChild(self.btmLabel);
    if self.loadingxml then
        CCArmatureDataManager:sharedArmatureDataManager():addArmatureFileInfoAsync(self.loadingpng, self.loadingplist, self.loadingxml, function (  )
            if self.isLoaded then
                return;
            end
            local lion = ObjectFactory.newArmature(self.animName);
            lion:setPosition(ccp(Screen.cx,Screen.cy));
            lion:addParent(self.uiLayer);
            lion:getComponent("Animation"):play("run", WrapMode.Loop);
        end)
    end

    -- 3. 添加到场景
    SceneM.dontDestroy(self.uiLayer);

    -- 4. 关掉触摸消息
    CCDirector:sharedDirector():getTouchDispatcher():setDispatchEvents(false);

    -- 5. 关掉动作管理
    CCDirector:sharedDirector():getActionManager():removeAllActions();

    -- 6. 退出当前场景
    if self.curScene then
        self.curScene:setVisible(false);
    end

    -- 7. 重新初始化管理类
    SceneM.uiLayers = {};

    -- 8.延迟清除当前资源,并且加载下一个场景资源 
    performWithDelay(function (  )
        self:cleanup();
        self:startLoading(self.config);
    end, 0.01)

    -- 9. 回收lua内存
    collectgarbage("collect")
end

function LoadingController:startLoading(theloadingconfig)
    if theloadingconfig == nil then
        self.isLoaded = true;
            -- 切换场景
            self.nextScene = ObjectFactory.newScene(self.curSceneName);
            SceneM.curScene = self.nextScene;
            self.nextScene:addComponent(self.curSceneName,SceneM.getSceneController(self.curSceneName));
            
            -- 关闭加载层
            SceneM.destroy(self.uiLayer);

            -- 开启触摸消息
            CCDirector:sharedDirector():getTouchDispatcher():setDispatchEvents(true);

            -- 记录配置文件路径
            SceneM.lastSceneName = self.curSceneName;

            -- 切换到新场景
            SceneM.replaceScene(self.nextScene, "crossfade", 0.2, Screen.COLOR_WHITE);
        return;
    end
    print ("start loading")
    self.loadingConfig = theloadingconfig;
    local resTypes = {"sounds","textures","atlas","animations","effects"}
    local curIndex = 1;
    -- 1.开始当前场景加载资源
    self.curLoadingNum = 0
    local totalNum  = 0
    local function loopRes( t , resType)
        if self.curLoadingNum > self.totalLoadingNum then
            return;
        end
        if t == nil then
            curIndex = curIndex + 1;
            local resType = resTypes[curIndex];
            print("加载类型:",resType);
            print("加载:",theloadingconfig[resType]);
            loopRes(theloadingconfig[resType], resType);
            return;
        end
        local keys = table.keys(t);
        totalNum = totalNum + #keys;
        local tempIndex = 1;
        local function loadRes(  )
            self.curLoadingNum = self.curLoadingNum + 1;
            if self.curLoadingNum > self.totalLoadingNum then
                return;
            end
            --print("====",self.curLoadingNum , totalNum)
            if self.curLoadingNum > totalNum then
                tempIndex = 1;
                curIndex = curIndex + 1;
                local resType = resTypes[curIndex];
                self.curLoadingNum = self.curLoadingNum - 1;
                loopRes(theloadingconfig[resType], resType);
                return;
            end
            local key = keys[tempIndex];
            local value = t[key];
            tempIndex = tempIndex + 1;
            if (tolua.type(value) == "table") then
                loopRes( value );
            elseif (tolua.type(value) == "string") then
                if resType == SOUNDTYPE then
                    -- 1.异步声音加载
                    --print("加载声音:", value);
                    Audio.preloadEffect(value);
                    performWithDelay(function (  )
                        loadRes();
                    end, CCDirector:sharedDirector():deltaTime())
                end

                if resType == TEXTURETYPE then
                    -- 2.异步纹理加载
                    --print("加载纹理:", value);
                    CCTextureCache:sharedTextureCache():addImageAsync(value, function ( )
                        self:CheckedResLoaded(); -- 检测下是否加载完毕
                        performWithDelay(function (  )
                            loadRes();
                        end, CCDirector:sharedDirector():deltaTime())
                    end);
                end

                if resType == ATLASTYPE then
                    -- 2.异步纹理加载
                    local png = string.gsub(value, ".plist", ".png")
                    --print("加载图集:",png);
                    CCTextureCache:sharedTextureCache():addImageAsync(png, function ( )
                        -- 添加plist 到 CCSpriteFrameCache
                        CCSpriteFrameCache:sharedSpriteFrameCache():addSpriteFramesWithFile(value)
                        self:CheckedResLoaded(); -- 检测下是否加载完毕
                        performWithDelay(function (  )
                            loadRes();
                        end, CCDirector:sharedDirector():deltaTime())
                    end);
                end

                if resType == ANIMATIONTYPE or resType == EFFECTTYPE then
                    --3.异步动画加载
                    local plist = string.gsub(value, ".xml", ".plist")
                    local png = string.gsub (value, ".xml", ".png")
                    --print("加载骨骼动画:",png, plist, value);
                    CCArmatureDataManager:sharedArmatureDataManager():addArmatureFileInfoAsync(png, plist, value, function (  )
                        self:CheckedResLoaded(); -- 检测下是否加载完毕
                        performWithDelay(function (  )
                            loadRes();
                        end, CCDirector:sharedDirector():deltaTime())
                    end)
                end
            end
        end

        loadRes();
    end
    -- 计算加载的资源总数
    local function size( config )
        return #table.keys(config.textures) 
        + #table.keys(config.sounds) 
        + #table.keys(config.fonts) 
        + #table.keys(config.animations)
        + #table.keys(config.atlas)
        + #table.keys(config.effects);
    end
    self.totalLoadingNum = size(theloadingconfig);

    -- 加载场景资源
    local resType = resTypes[curIndex];
    print("加载类型:",resType);
    print("加载:",theloadingconfig[resType]);
    loopRes(theloadingconfig[resType], resType);
end

-- 检测是否加载完毕
function LoadingController:CheckedResLoaded(  )
    if self.curLoadingNum <= self.totalLoadingNum then
        -- 1.更新当前进度
        local percent = math.modf(self.curLoadingNum * 100 / self.totalLoadingNum)
        self.btmLabel:setString(string.format("Loading %s%%", percent));
    end

    -- 2.检测下是否加载完毕
    if (self.curLoadingNum == self.totalLoadingNum) then
        local function onComplete(event)
            print ("loading res finished!")
            self.isLoaded = true;
            -- 切换场景
            self.nextScene = ObjectFactory.newScene(self.curSceneName);
            SceneM.curScene = self.nextScene;
            self.nextScene:addComponent(self.curSceneName,SceneM.getSceneController(self.curSceneName));
            
            -- 关闭加载层
            SceneM.destroy(self.uiLayer);

            -- 开启触摸消息
            CCDirector:sharedDirector():getTouchDispatcher():setDispatchEvents(true);

            -- 记录配置文件路径
            SceneM.lastSceneName = self.curSceneName;

            -- 切换到新场景
            SceneM.replaceScene(self.nextScene, "crossfade", 0.2, Screen.COLOR_WHITE);
        end
        -- 等待一帧 不然最后一次无法绘制
        performWithDelay(onComplete, CCDirector:sharedDirector():deltaTime() * 2);
    end
end

-- 清理资源
function LoadingController:cleanup(  )
    CCDirector:sharedDirector():getActionManager():removeAllActions();
    -- 获得上一个场景配置,根据配置删除
    if SceneM.lastSceneName then
        local lastConfig = res[SceneM.lastSceneName];
        local function removeRes( t , resType)
            if t == nil or type(t) ~= "table" then
                return;
            end
            for key, value in pairs(t) do    
                 if (tolua.type(value) == "table") then
                    loopRes( value );
                elseif (tolua.type(value) == "string") then
                    if resType == SOUNDTYPE then
                        -- 1.删除声音
                        Audio.unloadSound(value);
                    end

                    if resType == TEXTURETYPE then
                        -- 2.删除纹理
                        CCTextureCache:sharedTextureCache():removeTextureForKey(value);
                    end

                    if resType == ATLASTYPE then
                        -- 3.删除plist纹理
                        CCSpriteFrameCache:sharedSpriteFrameCache():removeSpriteFramesFromFile(value);
                        value = string.gsub(value, ".plist", ".png");
                        CCTextureCache:sharedTextureCache():removeTextureForKey(value);
                    end

                    if resType == ANIMATIONTYPE then
                        -- 4.删除动画
                        print("删除骨骼动画资源:",value);
                        value = string.gsub(value, ".xml", ".png");
                        CCTextureCache:sharedTextureCache():removeTextureForKey(value); 
                        value = string.gsub(value, ".png", ".plist");
                        CCSpriteFrameCache:sharedSpriteFrameCache():removeSpriteFramesFromFile(value); 
                        --CCArmatureDataManager:purge();
                    end
                end
            end 
        end
        removeRes(lastConfig.sounds, SOUNDTYPE);          --删除声音资源
        removeRes(lastConfig.textures, TEXTURETYPE);       --删除纹理资源
        removeRes(lastConfig.atlas, ATLASTYPE);           --删除图集资源
        removeRes(lastConfig.animations, ANIMATIONTYPE);    --删除动画资源
        removeRes(lastConfig.effects, ANIMATIONTYPE);    --删除动画资源

        -- 移除临时动态公共资源
        if ResM.tempPathCache then
            removeRes(ResM.tempPathCache.sounds, SOUNDTYPE);          --删除声音资源
            removeRes(ResM.tempPathCache.textures, TEXTURETYPE);       --删除纹理资源
            removeRes(ResM.tempPathCache.atlas, ATLASTYPE);           --删除图集资源
            removeRes(ResM.tempPathCache.animations, ANIMATIONTYPE);    --删除动画资源
        end
        ResM.init();
        
        CCTextureCache:sharedTextureCache():dumpCachedTextureInfo();
    end
    
    -- CCSpriteFrameCache:purgeSharedSpriteFrameCache();
    -- CCTextureCache:sharedTextureCache():removeAllTextures();
    -- CCArmatureDataManager:purge();
end

return LoadingController;
原文地址:https://www.cnblogs.com/newlist/p/3647660.html