使用Laya開發微信小遊戲時無法使用位圖字體解決方案

-前言-

依照Laya官方提供的位圖字體使用方案時,在本地是可以正常使用的。當發佈到微信小遊戲上就沒法使用。經過查找是缺少解析xml的庫。

-正文-

方案1:引入xml解析庫

缺少什麼我們就引入什麼,我們引入官方提供的js庫

//修改bin目錄下game.js文件
if ((typeof swan !== 'undefined') && (typeof swanGlobal !== 'undefined')) {
	require("swan-game-adapter.js");
	require("libs/laya.bdmini.js");
} else if (typeof wx!=="undefined") {
	require("weapp-adapter.js");
	require("libs/laya.wxmini.js");
}
window.loadLib = require;
require("index.js");
//添加解析庫
window.Parser = require("./js/dom_parser.js");

具體的解析庫就執行去找了。本文不是着重講解這個方案,這個方案有下面幾個缺點:

  • Parser可能會遭到全局變量污染,導致無法調用到我們想要的函數。
  • 我們始終都是拉取xml文件再進行解析,在瀏覽器層面數據傳輸xml的效率並不如json
  • 爲了解析xml我們會額外引入js文件,js文件需要被解析,增加了遊戲進入時間。

因此我們可以將Laya源代碼修改成使用json文件作爲數據配置文件。

方案2 修改laya.core.js實現json文件作爲fnt配置文件

1.xml到json的轉換

生成fnt及png

前面的步驟我們還是保持不變,依舊使用Laya官方提供的方式,使用bmfont這個軟件製作fnt位圖字體文件。製作好後我們將.fnt(實際內容是xml)及.png文件放到laya/assets/font文件夾下。

轉換.fnt文件到.json文件

首先這一步需要node環境及安裝gulp,如果沒有安裝環境首先安裝環境。這裏默認安裝了node環境。

//1.安裝gulp
npm install gulp --save-dev
//2.安裝轉檔所需依賴
npm install iconv-lite --save-dev
npm install xml-js

安裝好gulp後我們在項目根目錄新建一個gulpfile.js文件來寫我們的轉換代碼。

const fs = require("fs");
const x2j = require("xml-js");
const path = require("path");
const iconv = require("iconv-lite");
function xml2json(cb) {
    let allPath = [];
    readAll("./laya/assets/font/", allPath);
    for (let i = 0; i < allPath.length; i++) {
        let srcPath = allPath[i];
        if (srcPath.indexOf(".fnt") != -1) {
            //xml配置中可能存在中文,因此利用iconv-lite轉換爲GBK在進行轉檔
            let xmlData = fs.readFileSync(srcPath, {encoding:"binary"});
            let buf = new Buffer(xmlData,'binary');
            xmlData = iconv.decode(buf,'GBK');
            let jsonData = x2j.xml2json(xmlData,{
                compact:true,
                ignoreDeclaration:true,
                ignoreCdata:true,
                ignoreDoctype:true,
                ignoreComment:true,
                nativeType:true
            })
            let destPath = srcPath.replace(".fnt",".json");
            fs.writeFileSync(destPath,jsonData,"utf-8");
        }
    }
    cb();
}

/**
 * 讀取指定路徑下的所有文件路徑並賦值到out中
 * @param {string} parentPath 
 * @param {Array<string>} out 
 */
function readAll(parentPath, out) {
    try {
        let files = fs.readdirSync(parentPath);
        files.forEach(function (item) {
            let tempPath = path.join(parentPath, item);
            let stats = fs.statSync(tempPath);
            if (stats.isDirectory()) {
                readAll(tempPath, out);
            } else {
                out.push(tempPath);
            }
        });
    } catch (e) {
        console.warn("Path Error:" + e);
        return out;
    }
}
module.exports.xml2json = xml2json;

在gulpfile.js寫好之後我們在終端直接執行gulp xml2json就可轉檔。我們上面使用的是xml-js這個庫來實現的xml到json的轉換,上面傳給xml-js對象的參數不能變,否則後面解析json的代碼也要做適當修改,不然是讀取不到對應屬性的。

2.修改laya.core.js

我們找到BitmapFont類,在loadFont方法下面添加一個loadFontByJson的方法。

//loadFontByJson
__proto.loadFontByJson=function(path,complete){
    this._path=path;
    this._complete=complete;
    this._isFntType = false;
    if (!path || path.indexOf(".json")===-1){
        console.warn('Bitmap font configuration information must be a ".json" file');
        return;
    }
    Laya.loader.load([{url:path,type:"json"},
    {url:path.replace(".json",".png"),
    type:/*laya.net.Loader.IMAGE*/"image"}],
    Handler.create(this,this._onLoaded));
}
/**
*@private
*/
__proto._onLoaded=function(){
    if(this._isFntType){
        this.parseFont(Loader.getRes(this._path),Loader.getRes(this._path.replace(".fnt",".png")));
    }else{
        this.parseFontByJson(Loader.getRes(this._path),Loader.getRes(this._path.replace(".json",".png")));
    }
    this._complete && this._complete.run();
}

加載完成後依舊回調到_onLoaded方法,通過_isFntType標誌位來判斷我們改BitmapFont實例是通過哪種方式加載的。接下來就創建parseFontByJson方法來解析數據即可。

/**
 * 通過json解析字體
 */
__proto.parseFontByJson=function(jsonData,texture){
    if(jsonData==null || texture == null)return;
    this._texture=texture;
    var data = jsonData.font;
    var tX=0;
    var tScale=1;
    var tInfo = data.info._attributes;
    this.fontSize=parseInt(tInfo.size);
    var tPadding=tInfo.padding;
    var tPaddingArray=tPadding.split(",");
    this._padding=[parseInt(tPaddingArray[0]),parseInt(tPaddingArray[1]),parseInt(tPaddingArray[2]),parseInt(tPaddingArray[3])];
    var chars;
    chars=data.chars.char;
    var i=0;
    for (i=0;i < chars.length;i++){
        var tAttribute=chars[i]._attributes;
        var tId = tAttribute.id;
        var xOffset=parseInt(tAttribute.xoffset) / tScale;			
        var yOffset=parseInt(tAttribute.yoffset) / tScale;
        var xAdvance=parseInt(tAttribute.xadvance) / tScale;
        var region=new Rectangle();
        region.x=parseInt(tAttribute.x);
        region.y=parseInt(tAttribute.y);
        region.width=parseInt(tAttribute.width);
        region.height=parseInt(tAttribute.height);
        var tTexture=Texture.create((texture),region.x,region.y,region.width,region.height,xOffset,yOffset);
        this._maxWidth=Math.max(this._maxWidth,xAdvance+this.letterSpacing);
        this._fontCharDic[tId]=tTexture;
        this._fontWidthMap[tId]=xAdvance;
    }
}

修改完JS代碼之後,我們需要在.d.ts中添加這個類的聲明,不然Ts調用的時候編輯器會報錯。
在LayaAir.d.ts文件中找到BitmapFont類聲明,在下面添加方法接口

/**
 * 通過指定位圖字體文件路徑,加載位圖字體文件,加載完成後會自動解析。
 * @param path json路徑
 * @param complete 完成回調
 */
loadFontByJson(path: string, complete: Handler): void;

至此我們所有需要修改的代碼都修改完成了。外部調用直接調用loadFontByJson即可。

-結語-

在修改完下來,其實我們可以發現,Laya使用位圖字體其實也是根據一張大紋理去索引uv去獲取具體字的紋理數據。這跟圖集實現基本是一樣的,只是在外部調用設置Text會更加方便而已。
另外位圖字體不能修改顏色(只能通過濾鏡),改變字體大小(通過Scale修改大小)。追根溯源是因爲這時候我們的字體已經不是渲染後的文字,是無法修改其屬性,正常字體是拿着我們要修改的字體屬性到Canvas繪圖生成的,因此不能修改也是情有可原。因此想要使用位圖字體的朋友們想清楚再使用。

任何一個小東西都蘊藏的無數的坑~~
原文鏈接:http://dengxuhui.cn/#html/blog/f02dea819604943226c8c7a247a8eb1a

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