1. 程式人生 > >egret外掛使用案例

egret外掛使用案例

2018年8月13日,白鷺引擎釋出5.2.7 版本。本次版本主要新增了兩大功能:命令列增加自動合圖外掛TextureMergerPlugin,微信小遊戲支援庫增加二進位制和聲音快取方案。

同時,本次版本還是對 5.2 版本的一次集中性缺陷修復,更新修復了大家反饋的涉及2D渲染- JavaScript、AssetsManager、微信小遊戲支援庫的數個BUG。在此,我們要再次特別感謝開發者們通過Egret社群、白鷺引擎小遊戲開發微信群等渠道提交的BUG反饋。

據小編了解,5.2.7版本中新增的自動合圖外掛可以幫助開發者在開發期使用碎圖,在釋出後將碎圖自動整合為整圖釋出,提高開發者開發和釋出的效率,完善整個開發和釋出的工作流。
由於原有的檔案快取方案只快取了圖片和文字資源,所以這次微信小遊戲支援庫新增的二進位制和聲音快取方案,解決遊戲第二次進入不重新載入資源問題,節省資源伺服器費用,提高使用者體驗。

引言

本文不詳細介紹各外掛的細節,只展示使用方法,如果開發者對細節有興趣可以參考 文件

為了讓開發者以更簡單的使用Egret內建的外掛,我們將通過一個案例來展示外掛的具體使用方法和注意事項。

本文案例從一個剛編寫完成的eui卡牌專案開始釋出到微信小遊戲,為了讓程式碼包的體積更小更好管理,逐步新增使用不同的外掛,以實現不同的需求。

todos

  • 使用UglifyPlugin將程式碼混淆壓縮

  • 使用ResSplitPlugin把部分資源分離出去

  • 使用ZipPlugin把檔案壓縮成zip格式

  • 使用TextureMergerPlugin將紋理合並,且用ConvertResConfigFilePlugin修改res.json配置檔案

專案初始化

  1. 把index.html中的data-scale-mode改成fixedWidth

  2. 開啟EgretLauncher,將本專案釋出成微信小遊戲

  3. 開啟微信開發者工具

使用UglifyPlugin壓縮程式碼

在微信開發者工具可以看到,js資料夾中5個庫檔案和一個main.js

現在需求是是要把庫檔案壓縮到一個檔案lib.min.js中。

回到EgretWing,編輯sctipts下的config.wxgame.ts:

//***其他程式碼***
//
​
if(command=='build') {
   return{
       outputDir,
       commands: [
           // 清理js,resource資料夾
           newCleanPlugin({ matchers: ["js", "resource"] }),
           newCompilePlugin({ libraryType: "debug", defines: { DEBUG: true, RELEASE: false} }),
           newExmlPlugin('commonjs'), // 非 EUI 專案關閉此設定
           newWxgamePlugin(),
​
           // 壓縮外掛
           newUglifyPlugin([
              {
                   // 需要被壓縮的檔案
                   sources: [
                       "libs/modules/egret/egret.js",
                       "libs/modules/eui/eui.js",
                       "libs/modules/assetsmanager/assetsmanager.js",
                       "libs/modules/tween/tween.js",
                  ],
                   // 壓縮後的檔案
                   target: "lib.min.js"
              }
          ]),
​
           newManifestPlugin({ output: 'manifest.js'})
      ]
  }
  }
​
//
// ***其他程式碼***

儲存後在終端執行:

egret build

可以在微信開發者工具看到釋出後的程式碼,js資料夾內的庫檔案已經被壓縮到lib.min.js。

但是報錯,找不到eui,這是因為自動生成的manifest.js裡面對js的引用順序出錯,需要優先引用lib.min.js

開啟根目錄下的manifest.js, 修改一下引用順序。

require("js/lib.min.js")
require("js/main.js")
require("js/default.thm.js")

每次編譯的時候manifest.js都會被重新生成,所以我們使用一個自定義指令碼來修改他們的順序

開啟 scripts下的myPlugin.ts :

/**
* 示例自定義外掛,您可以查閱 http://developer.egret.com/cn/2d/projectConfig/cmdExtensionPluginin/ 
* 瞭解如何開發一個自定義外掛
*/
exportclassCustomPluginimplementsplugins.Command{
   privatebuffer
   constructor() {
  }
​
   asynconFile(file: plugins.File) {
       // 儲存manifest.js檔案的內容
       if(file.basename.indexOf('manifest.js') >-1) {
           this.buffer=file.contents
      }
       returnfile;
  }
​
   asynconFinish(commandContext: plugins.CommandContext) {
       // 把'lib.min.js'移到第一位
       
       if(this.buffer) {
           letcontents: string=this.buffer.toString()
           letarr=contents.split('\n')
           letlib=null
           arr.forEach((item, index) =>{
               if(item.indexOf('lib.min.js') >-1) {
                   lib=item
                   arr.splice(index, 1)
              }
          })
           if(lib!=null) {
               arr.unshift(lib)
          }
​
           letnewCont=arr.join('\n')
           commandContext.createFile('manifest.js', newBuffer(newCont))
      }
  }
}

這個檔案就是用來自定義外掛的,在config.wxgame.ts中已經預設引用,所以只需要呼叫即可,注意呼叫順序

newManifestPlugin({ output: 'manifest.js'}),
// 在manifest.js生成之後呼叫
newCustomPlugin()

使用ResSplitPlugin分離資原始檔

因為微信對程式碼包的大小是有限制的,總大小不能超過4M(使用分包功能可以提升到8M),所以我們需要通過ResSplitPlugin把某些遊戲資原始檔分離出去,將遊戲資源放置在一個外部CDN伺服器上,需要的時候動態載入即可。

編輯config.wxgame.ts:

// ***其他程式碼***
//
​
newResSplitPlugin({
   verbose: false, matchers:
  [
       // from 使用glob表示式來匹配檔案, projectName就是專案的名字
      { from: "resource/art/about/**.**", to: `${projectName}_wxgame_remote`},
      { from: "resource/art/heros_goods/**.**", to: `${projectName}_wxgame_remote`}
  ]
})
​
// ***其他程式碼***

儲存後在終端執行:

egret build

微信開發者工具中resource > art 下的aboutheros_goods已經不在了。

被分離出去的在專案根目錄中 egret-eui-demo_wxgame_remote 資料夾內。

使用ZipPlugin把檔案壓縮成zip格式

為了減少載入次數和傳輸量,我們可以把檔案壓縮成zip格式,使用的時候可以使用第三方庫JSZip來讀取使用zip檔案。

使用ZipPlugin外掛之前,需要安裝cross-zip 和 cross-zip-cli , 在終端中輸入:

//全域性安裝
npminstall cross-zip -g  
npminstall cross-zip-cli -g

安裝完成之後,在config.wxgame.ts新增程式碼:

newZipPlugin({
   mergeSelector: p=>{
       // 如果檔案是assets/路徑下的, 壓縮到assets.zip
       if(p.indexOf("assets/") >=0) {
           return"assets.zip"
      }
  }
})

專案中其實assets裡面的資源都是沒有用到的,這裡我們用它來演示壓縮外掛的使用。

儲存後在終端執行:

egret build

執行之後可以在微信開發者工具看到,resource目錄下原來的assets資料夾已經被壓縮成了assets.zip。

使用TextureMergerPlugin,ConvertResConfigFilePlugin合併紋理集

專案中使用的圖片資源都是單獨的png檔案,在載入的時候每張圖片都會單獨請求。我們可以通過合併紋理集的方式把這些圖片合成一張圖,以減少請求數量。使用外掛之前,我們需要有紋理集的配置檔案tmpropject, 可以用兩種方式生成:

這裡使用第二種方法,使用指令碼autoMerger.js:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true});
varfs=require("fs");
varpath=require("path");
varresjsons=["resource/default.res.json"]; //要掃描的res.json檔案
vartargetDir="resource/TextureMerger"; //輸出目錄
varpathNor=path.relative(targetDir, "resource"); //返回一個相對路徑
vartempindex=0;
//建立輸出資料夾
if(resjsons.length>0) {
   if(!fs.existsSync(targetDir)) {
​
       // var paths = path.normalize(targetDir).split("\\");   //windows 下使用
       varpaths=path.normalize(targetDir).split("\/");   //mac linux 下使用
​
       vartarget=".";
       for(var_i=0, paths_1=paths; _i<paths_1.length; _i++) {
           varp=paths_1[_i];
​
           // target += ("\\" + p); // windows 下使用
           target+=("\/"+p);  // mac linux 下使用
​
           if(!fs.existsSync(target))
               // 根據路徑建立資料夾
               fs.mkdirSync(target);
      }
  }
}
var_loop_1=function(resJson) {
   // 判斷是否是res.json檔案
   if(fs.existsSync(resJson) &&resJson.indexOf("res.json") >-1) {
       vardefaultJson=fs.readFileSync(resJson, "utf-8");
       // 解析res.json檔案內容
       vardefaultObject=JSON.parse(defaultJson);
       vargroups=defaultObject.groups; //組
       varresources=defaultObject.resources; //資源
       varresourcesHash_1={}; // 用來存放resources的資源資訊
​
       // 遍歷resources
       for(var_i=0, resources_1=resources; _i<resources_1.length; _i++) {
           varresource=resources_1[_i];
           resourcesHash_1[resource.name] =resource.url;
      }
​
       // 遍歷groups
       for(var_a=0, groups_1=groups; _a<groups_1.length; _a++) {
           vargroup=groups_1[_a];
           vartmproject={}; //用來存放tmproject檔案的資訊
           // tmproject檔案配置
           tmproject["options"] ={
               "layoutMath": "2",
               "sizeMode": "2n",
               "useExtension": 1,
               "layoutGap": 1,
               "extend": 0
          };
           // projectName
           tmproject["projectName"] =group.name+"_"+tempindex; 
           // 版本
           tmproject["version"] =5;
           tempindex++;
​
           // 獲取res.json分組的keys, 並分割成陣列
           varoldkeys=group.keys.split(","); 
           varoldkeysHash={};
           // 遍歷oldkeys
           for(var_b=0, oldkeys_1=oldkeys; _b<oldkeys_1.length; _b++) {
               varkey=oldkeys_1[_b];
               // 儲存到oldkeysHash物件中
               oldkeysHash[key] =true;
          }
​
           varnewKeys=[];
           // 遍歷oldkeys
           for(var_c=0, oldkeys_2=oldkeys; _c<oldkeys_2.length; _c++) {
               varkey=oldkeys_2[_c];
               if(key.indexOf("json") ==-1) {
                   if(!oldkeysHash[key.replace("png", "json")]) { //粒子和龍骨對應的圖集不合圖
                       if(!oldkeysHash[key.replace("png", "fnt")]) //點陣圖字型
                           newKeys.push(key);
                  }
                   elseif(key.indexOf("jpg") >-1) {
                       newKeys.push(key);
                  }
              }
          }
           oldkeysHash={};
           oldkeys=[];
           // files路徑
           varurls=newKeys.map(function(key) {
               returnpath.join(pathNor, resourcesHash_1[key]);
          });
           tmproject["files"] =urls;
           // 根據tmproject寫入檔案
           if(urls.length>0) {
               fs.writeFileSync(path.join(targetDir, tmproject["projectName"] +".tmproject"), JSON.stringify(tmproject));
          }
           tmproject={};
      }
  }
};
//根據陣列開始掃描
for(var_a=0, resjsons_1=resjsons; _a<resjsons_1.length; _a++) {
   varresJson=resjsons_1[_a];
   _loop_1(resJson);
}
​
把這個指令碼放在scripts資料夾內,這個指令碼是根據專案的default.res.json檔案的內容來生成tmpropject檔案

在終端中執行:

nodescripts/autoMerger.js

執行成功之後可以在resource資料夾中看到多出了一個TextureMerger資料夾,裡面就是根據default.res.json分組生成的tmpropject檔案。

現在只需要執行TextureMergerPlugin外掛就可以自動合併,這裡需要注意TextureMergerPlugin依賴 TextureMerger 1.7 以上的版本,如果不符合請自行安裝,並且在執行時TextureMerger需要處於關閉狀態。

newTextureMergerPlugin({textureMergerRoot:[ 'resource']})

儲存後在終端執行:

egret build

執行完成後,在微信開發者工具可以看到,resource > TextureMerger 內新增了三個png檔案,就是合併之後的紋理集。遊戲執行的時候只需要載入這三個紋理集就可以,無需載入那些單獨的png檔案但是需要去res.json裡面配置,把單獨的資源引用都刪除,加上紋理集的引用。

這些操作當然不需要手動去完成,現在只需要使用ConvertResConfigFilePlugin外掛就可以實現這個功能。

編輯config.wxgame.ts:

newTextureMergerPlugin(),
​
newConvertResConfigFilePlugin({
   resourceConfigFiles: [{ filename: "resource/default.res.json", root: "resource/"}],
   nameSelector: (p) =>{
        returnpath.basename(p).split(".").join("_")
  },
   TM_Verbose: true
})

儲存後在終端執行:

egret build

在微信開發者工具中,開啟偵錯程式,在network面板可以看到載入的紋理集。

這裡有個注意事項,在遊戲中點選英雄按鈕,切換到英雄場景時,會發現列表裡面的圖片載入不出來。

在network面板可以看到載入請求是單獨的png檔案,而不是紋理集。

這是因為列表中的圖片地址是直接使用url。

// 原始陣列
letdataArr:any[] =[
  {image: 'resource/art/heros_goods/heros01.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false},
  {image: 'resource/art/heros_goods/heros02.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false},
  {image: 'resource/art/heros_goods/heros03.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: true},
  {image: 'resource/art/heros_goods/heros04.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false},
  {image: 'resource/art/heros_goods/heros05.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false},
  {image: 'resource/art/heros_goods/heros06.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false},
  {image: 'resource/art/heros_goods/heros07.png', name: '亞特伍德', value: '評價: 很特麼厲害, 為所欲為', isSelected: false}
]
// 轉成eui資料
leteuiArr:eui.ArrayCollection=neweui.ArrayCollection(dataArr)
// 把list_hero資料來源設定成euiArr
this.list_hero.dataProvider=euiArr
// 設定list_hero的項呈視器 (這裡直接寫類名,而不是寫例項)
this.list_hero.itemRenderer=heroList_item

這種引用方式的圖片,需要開發者手動在程式碼中修改,將圖片地址修改成紋理集中的圖片。

結語

本文通過使用UglifyPlugin,ResSplitPlugin,ZipPlugin,TextureMergerPlugin,ConvertResConfigFilePlugin外掛,使專案釋出到微信小程式之後的程式碼包體積減小,使用者發起的請求數變少,且將程式碼混淆壓縮。

使用Egret自帶的外掛,已經可以滿足開發者的基本需求,如果有針對專案的特殊需求,可以選擇自定義外掛