CreatorPrimer|編寫一個版本號元件
在集合類遊戲中,不論是大廳還是子游戲都會涉及到版本的更新,在開發除錯階段,檢查更新是否生效的一個直觀的方法就是觀察版本號的變化,因此版本號的顯示是遊戲中不可缺少的細節,特別是集合類遊戲。
1. 熟悉manifest
這裡我們使用 Cocos Creator 提供的 AssetsManager 熱更新框架所要求的 project.manifest 它是一個JSON格式的配置檔案:
{ "version": "0.0.1", "packageUrl": "http://192.168.1.100/update", "remoteManifestUrl": "http://192.168.1.100/update/hall-project.manifest", "remoteVersionUrl": "http://192.168.1.100/update/hall-version.manifest", "assets": {} }
上面是一個hall-project.manifest,再看一個game-project.manifest內容如下:
{ "version": "0.1.1", "packageUrl": "http://192.168.1.100/update", "remoteManifestUrl": "http://192.168.1.100/update/game-project.manifest", "remoteVersionUrl": "http://192.168.1.100/update/game-version.manifest", "assets": {} }
獲取版本號,其實就是讀取 manifest 中的 version 欄位,顯示到一個 cc.Label 元件上。這對大多數人來說都是小菜一碟,但是Shawn發現,利用元件方式實現一個相對通用的版本號元件做法卻並不多見。
2. VersionLabel元件
瞭解過 manifest,我們就可以開始動手編寫一個基於 Cocos Creator 引擎提供的 AssetsManager 熱更新框架的版本號元件,這裡將元件取名為“VersionLabel”,先看一下元件提供的屬性介面:
對於元件的使者關心的是ModuleName屬性,當你想顯示不同遊戲模組的版本時,只需要指定正確的ModuleName就可以了,下面是元件程式碼:
cc.Class({ extends: cc.Component, editor: CC_EDITOR && { requireComponent: cc.Label, //強制依賴cc.Label元件 }, properties: { default: '0.0.0', moduleName: { default: '', notify(oldValue) { if (CC_EDITOR || oldValue === this.moduleName) { return; } this._updateContent(); } } }, start () { //獲取Label元件 this.label = this.getComponent(cc.Label); //更新版本內容 this._updateContent(); }, /** * 更新內容 */ _updateContent() { //載入“resources/manifest/xxx-project.manifest” let url = `manifest/${this.moduleName}-project`; this._getManifestContent(url, (content) => { this._setVersion(content); }); }, /** * * @param {String} urlresources以下路徑 * @param {Function} cb非同步回撥函式,返回manifest上下文 */ _getManifestContent(url, cb) { cc.loader.loadRes(url, cc.Asset, null, (error, asset) => { if (error) { cb(null); return; } //通過nativeUrl讀取檔案內容 let content = cc.loader.getRes(asset.nativeUrl); cb(content); }); }, /** * 設定Label文字 * @param {String} content */ _setVersion(content) { let data; try { data = JSON.parse(content); this.label.string = data.version; } catch(e) { cc.warn(e); this.label.string = this.default; } } });
簡單說明一下上面的程式碼:
1. 該元件提供了一個moduleName的屬性,這裡注意不要使用name屬性,因為是‘name’是Cocos Creator元件內建屬性,還有定義manifest檔案需要按照一定檔名命規範,我這裡的名命模版是“xxx-project.manifest”
2. 我們是將版本號文字顯示到Label元件上,因此requireComponent: cc.Label 是定義該元件強制依賴cc.Label元件。使用它的好處是,當直接將該指令碼拖動到場景或層級管理器時,會自動掛載一個cc.Label元件,增強元件的使用體驗。
3. manifest檔案是放在resources目錄下的,雖然manifest內部是json格式,但目前cc.loader還不能直接解析manifest這個副檔名的檔案內容,當使用cc.loader.loadRes載入後,只能獲取到檔案的基本資訊,通過使用cc.loader.getRes(asset.nativeUrl)獲取檔案內容。
3. 讀取搜尋路徑下的manifest
上面的元件程式碼還存在一個Bug,我們是讀取的安裝包中的manifest檔案,看下面程式碼:
let url = `manifest/${this.moduleName}-project`;
此檔案存在於 resources 目錄,當執行在原生裝置上它是存在於安裝路徑中,當遊戲通過熱更新下載了新的 manifest 檔案,此路徑是否還正確呢?當然就不對了,我們需要讀取熱更新包中的 manifest 檔案才能獲得正確的版本號,看下面程式碼:
cc.Class({ extends: cc.Component, ... /** * 更新內容 */ _updateContent() { //如果為原生環境,嘗試載入可寫路徑下的xxx-project.manifes檔案 if (cc.sys.isNative) { let remoteAssets = cc.path.join(jsb.fileUtils ? jsb.fileUtils.getWritablePath() : '/', 'remote-assets'); let url = cc.path.join(remoteAssets, this.moduleName, '-project.manifest'); //使用jsb函式讀取檔案內容 let content = jsb.fileUtils.getStringFromFile(url); if (content) { this._setVersion(content); return; } } let url = `manifest/${this.moduleName}-project`; this._getManifestContent(url, (content) => { this._setVersion(content); }); }, ... });
上面程式碼在_updateContent函式中檢查當前如果為原生環境,先嚐試讀取 可寫路徑/remote-assets/xxx-project.manifest
檔案,如果檔案內容不存在才讀取安裝包resources目錄下的manifest檔案。
需要注意的是 remote-assets
是使用AssetsManager下載熱更新包時指定的,你需要根據自己的實際情況設定正確的路徑。
4. 小結
讀取版本號這個邏輯上下文只需要關心到那裡去獲取版本字串,使用元件的方式,可以將很多邏輯細節程式碼封裝到一段小程式碼中獨立執行,以達到與其它程式碼老死不相往來,從而有效減少耦合。
同時藉助Cocos Creator的視覺化屬性面板暴露介面,可以讓非程式設計師也能輕鬆使用元件搭建出遊戲內容,不知道大家獲取版本號是如何實現的呢,也歡迎分享你的實現方案。