-前言-
依照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