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”,先看一下組件提供的屬性接口:

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} url      resources以下路徑
     * @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的可視化屬性面板暴露接口,可以讓非程序員也能輕鬆使用組件搭建出遊戲內容,不知道大家獲取版本號是如何實現的呢,也歡迎分享你的實現方案。


奎特爾星球

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章