Cocos2d-html5 plist優化 & plist文件加載解析

目前h5引擎正在處於研究階段,基於Cocos2d-html5封裝一個TS版的引擎庫。

前言

以前在封裝UI及Scene這塊的內容,UI部分涉及到加載素材,也瞭解到cocos能夠直接使用TexturePacker合成後的plist文件及png。可是對於H5的項目來講,減小網絡請求是很重要的一步,特別是在頁面初始化加載的時候。這時候在官網看到以下內容:cc.spriteFrameCache 改造說明
通俗來講,就是在知道SpriteFrame的數據結構以後,提早將plist文件的解析(這樣能夠作到將多個plist文件集合到一個文件中,減小加載次數)。官網有一個作法:html

  • 提取n個plist文件至一個xx.pkgJson文件中,文件加載完畢後,使用自定義的_pkgJsonLoader對文件內容再次處理

我在按照此方法的處理過程當中,發現_pkgJsonLoader中對數據結構處理的不多,只是作了數據提取部分。因此我的以爲在生成.pkgJson文件時,就能夠直接按照SpriteFrame數據結構來生成數據,沒有必要通過兩次處理。如下是官網提供的思路:html5

// SpriteFrame數據結構
{
    _inited : true,
    frames : {
        "a_frame_0.png" : {
            rect : {x : 0, y : 0, width : 1, height : 1},
            rotated : false,
            offset : {x : 0, y : 0},
            size : {width : 1, height : 1}
            aliases : ["a_f_0"]
        }
    },
    meta : {
        image : "a.png"
    }
}
// pkgJsonLoader核心代碼
cc._pkgJsonLoader = {
    /**
     * @constant
     */
    _parse : function(data){
        var KEY = data instanceof Array ? this.MIN_KEY : this.KEY;
        var frames = {}, meta = data[KEY.meta] ? {image : data[KEY.meta][KEY.image]} : {};
        var tempFrames = data[KEY.frames];
        for (var frameName in tempFrames) {
            var f = tempFrames[frameName];
            var rect = f[KEY.rect];
            var size = f[KEY.size];
            var offset = f[KEY.offset];
            frames[frameName] = {
                rect : {x : rect[0], y : rect[1], width : rect[2], height : rect[3]},
                size : {width : size[0], height : size[1]},
                offset : {x : offset[0], y : offset[1]},
                rotated : f[KEY.rotated],
                aliases : f[KEY.aliases]
            }
        }
        return {_inited : true, frames : frames, meta : meta};
    },
    load : function(realUrl, url, res, cb){
        var self = this, locLoader = cc.loader, cache = locLoader.cache;
        locLoader.loadJson(realUrl, function(err, pkg){
            if(err) return cb(err);
            var dir = cc.path.dirname(url);
            for (var key in pkg) {
                var filePath = cc.path.join(dir, key);
                cache[filePath] = self._parse(pkg[key]);
            }
            cb(null, true);
        });
    }
};

cocos-pkgjson

上面說了那麼多,首先須要解決的是plist數據解析的工具,惋惜在官網上只提供瞭解析後的數據結構,沒有解析工具。爲此我在中文論壇及其它相關論壇都問了一遍,可是沒有獲得滿意的答覆。因此,決定本身造個輪子。我在npm上找到了plist包,試用了以後,發現plist能夠將plist文件的數據提取出來,數據結構以下:npm

{
    "frames": {
        "0.png": {
            "aliases": [
                
            ],
            "spriteOffset": "{0,0}",
            "spriteSize": "{64,49}",
            "spriteSourceSize": "{64,49}",
            "textureRect": "{{1,55},{64,49}}",
            "textureRotated": false
        },
        "1.png": {
            "aliases": [
                
            ],
            "spriteOffset": "{0,0}",
            "spriteSize": "{67,52}",
            "spriteSourceSize": "{67,52}",
            "textureRect": "{{1,1},{67,52}}",
            "textureRotated": false
        }
    },
    "metadata": {
        "format": 3,
        "pixelFormat": "RGBA8888",
        "premultiplyAlpha": false,
        "realTextureFileName": "radio.png",
        "size": "{69,105}",
        "smartupdate": "$TexturePacker:SmartUpdate:305947cb63527c2d3a81c456831d3508:0ffe9fa733c7901a53ebea001548ed6d:eed519fbbdd46973eb5ec3b717bd80b1$",
        "textureFileName": "radio.png"
    }
}

其實,到了這一步,我要作的東西就很簡單了。基於plist轉換後的結構,提取出SprimeFrame須要的數據便可。提取結果:json

{
    "_inited": true,
    "frames": {
        "0.png": {
            "rect": {
                "x": 1,
                "y": 55,
                "width": 64,
                "height": 49
            },
            "rotated": false,
            "offset": {
                "x": 0,
                "y": 0
            },
            "size": {
                "width": 64,
                "height": 49
            },
            "aliases": [
                
            ]
        },
        "1.png": {
            "rect": {
                "x": 1,
                "y": 1,
                "width": 67,
                "height": 52
            },
            "rotated": false,
            "offset": {
                "x": 0,
                "y": 0
            },
            "size": {
                "width": 67,
                "height": 52
            },
            "aliases": [
                
            ]
        }
    },
    "meta": {
        "image": "radio.png"
    }
}

配合自定義的cc._pkgJsonLoader:緩存

cc._pkgJsonLoader = {
    load: function (realUrl, url, res, cb) {
        var self = this, locLoader = cc.loader, cache = locLoader.cache;
        locLoader.loadJson(realUrl, function (err, pkg) {
            if (err) return cb(err);
            var dir = cc.path.dirname(url);
            for (var key in pkg) {
                var filePath = cc.path.join(dir, key);
                cache[filePath] = pkg[key];
            }
            cb(null, true);
        });
    }
};

cc.loader.register(["pkgJson"], cc._pkgJsonLoader);

問題解析

可能不瞭解的人會有疑問,爲何要處理plist,有什麼優勢呢?

其實以前提到過一部分,在此重點再說一次:網絡

  • 減小網絡請求——原先遊戲在啓動時,要將plist文件所有加載完成(不清楚到底有多少個),如今講n個plist集成到一個.pkgJson文件中,一次網絡請求便可
  • 避免解析數據——原有的plist文件加載完成後,底層還須要再次解析,而如今,.pkgJson中的內容就是直接可用的

cocos加載png plist時發生了什麼

這部分是在和同事交流時發現一位使用了cocos好久的開發,對此過程當中到底發生了什麼也不太瞭解。數據結構

png(其它圖片資源也是一樣的狀況)

  • 發起加載png資源的請求
  • cc.loader.cache緩存對應數據
  • cc.textureCache._textures緩存對應數據

plist

  • 發起加載plist資源的請求
  • cc.loader.cache緩存對應數據

此時,cc.loader.cache存儲的仍是xml中的內容:
當咱們使用以下命令是:cc.spriteFrameCache.addSpriteFrames("xx.plist");工具

  • 獲取plist對應的內容this

    • 未初始化:解析數據,解析完數據後添加:"_inited": true屬性,標記解析完成
    • 已初始化:直接使用數據
  • 從plist對應的圖片資源中加載資源(這個時候使用cc.textureCache._textures,若是沒有數據,會發起一次網絡請求)
  • 將spriteFrame存儲至_spriteFrames;
相關文章
相關標籤/搜索