Cocos Creator 远程加载 BMFont 方案

1,943 阅读3分钟
  1. 简介

本文介绍了如何通过远程加载 BMFont 来使用自定义字体。BMFont 是一种字体文件格式,它可以将字体转换为位图字体,从而在游戏中使用。

  1. 步骤

    1.   物料准备

      • quiz_font.fnt BMFont 主文件
      • quiz_font.png BMFont 纹理文件
    1.   BMFont JSON 文件提取

      • 将 quiz_font.fnt 文件拖入 cocos 任意目录中 (爆红不用管),然后右键点击 quiz_font,选择前往 library中的资源位置
      • 将该文件复制并重命名为 quiz_font.json,添加到我们的物料中, 此时将 quiz_font.json,quiz_font.png 上传到tos(云端)即可
      • 然后删除 quiz_font.fnt
  1. 主代码

    1.   FontAtlas 类

      • FontAtlas 类用于记录字母在字体图片纹理中的位置信息和在文本中的偏移量信息。
    1.   FontAtlas 的属性

      • _letterDefinitions: 记录字母信息的对象
      • _texture: 字体图片纹理
    1.   FontLetterDefinition 类

      • FontLetterDefinition 类用于记录字母在字体图片纹理中的位置信息和在文本中的偏移量信息。
    1.   FontLetterDefinition 的属性

      • u: 字母在纹理图片中的 x 坐标
      • v: 字母在纹理图片中的 y 坐标
      • w: 字母占用纹理图片的宽度
      • h: 字母占用纹理图片的高度
      • offsetX: 字母在文本中的 x 偏移量
      • offsetY: 字母在文本中的 y 偏移量
      • textureID: 纹理图片的 ID
      • valid: 字母是否有效
      • xAdvance: 字母的 x 方向偏移量
    1.   FontAtlas 的原型方法

      • addLetterDefinitions(letter, letterDefinition): 添加字母信息
      • cloneLetterDefinition(): 克隆字
      • getTexture(): 获取字体图片纹理
      • getLetter(key): 获取指定字母的信息
      • getLetterDefinitionForChar(char): 获取指定字符的字母信息
      • clear(): 清空字母信息
    1.   加载远端字体

      // 定义 FontAtlas 类
      let FontAtlas = function (texture) {
        this._letterDefinitions = {}; // 记录字母信息的对象
        this._texture = texture; // 字体图片纹理
      };
      
      // 定义 FontLetterDefinition 类
      let FontLetterDefinition = function () {
        this.u = 0; // 字母在纹理图片中的 x 坐标
        this.v = 0; // 字母在纹理图片中的 y 坐标
        this.w = 0; // 字母占用纹理图片的宽度
        this.h = 0; // 字母占用纹理图片的高度
        this.offsetX = 0; // 字母在文本中的 x 偏移量
        this.offsetY = 0; // 字母在文本中的 y 偏移量
        this.textureID = 0; // 纹理图片的 ID
        this.valid = false; // 字母是否有效
        this.xAdvance = 0; // 字母的 x 方向偏移量
      };
      
      // FontAtlas 的原型方法
      FontAtlas.prototype = {
        constructor: FontAtlas,
        // 添加字母信息
        addLetterDefinitions(letter, letterDefinition) {
          this._letterDefinitions[letter] = letterDefinition;
        },
        // 克隆字母信息
        cloneLetterDefinition() {
          let copyLetterDefinitions = {};
          for (let key in this._letterDefinitions) {
            let value = new FontLetterDefinition();
            cc.js.mixin(value, this._letterDefinitions[key]);
            copyLetterDefinitions[key] = value;
          }
          return copyLetterDefinitions;
        },
        // 获取字体图片纹理
        getTexture() {
          return this._texture;
        },
        // 获取指定字母的信息
        getLetter(key) {
          return this._letterDefinitions[key];
        },
        // 获取指定字符的字母信息
        getLetterDefinitionForChar(char) {
          let key = char.charCodeAt(0);
          let hasKey = this._letterDefinitions.hasOwnProperty(key);
          let letter;
          if (hasKey) {
            letter = this._letterDefinitions[key];
          } else {
            letter = null;
          }
          return letter;
        },
        // 清空字母信息
        clear() {
          this._letterDefinitions = {};
        },
      };
      
      // 加载远端字体
      loadRemoteFont(node) {
        // 加载字体图片纹理和配置文件
        const fontTexture = await getResource('/font/quiz_font.png');
        const fontJson = await getResource('/font/quiz_font.json');
        //  node 需要添加字体的节点·
        if (node) {
          if (node.getComponent(cc.Label)) {
            const sf = new cc.SpriteFrame(); // 创建精灵帧对象
            sf.setTexture(fontTexture, null, false, null, null); // 设置精灵帧的纹理
      
            const bf = new cc.BitmapFont(); // 创建位图字体对象
      
            bf['_fntConfig'] = fontJson.json._fntConfig;
            bf['spriteFrame'] = sf;
            // 可写可不写
            bf['fontSize'] = fontJson.json._fntConfig.fontSize;
      
            const fontAtlas = new FontAtlas(fontTexture); // 创建字体图集对象
      
            let fntConfig = fontJson.json._fntConfig;
            let fontDict = fntConfig.fontDefDictionary;
            for (let fontDef in fontDict) {
              let letter = new FontLetterDefinition(); // 创建字母信息对象
      
              let rect = fontDict[fontDef].rect;
              letter.offsetX = fontDict[fontDef].xOffset;
              letter.offsetY = fontDict[fontDef].yOffset;
              letter.w = rect.width;
              letter.h = rect.height;
              letter.u = rect.x;
              letter.v = rect.y;
              //FIXME: only one texture supported for now
              letter.textureID = 0;
              letter.valid = true;
              letter.xAdvance = fontDict[fontDef].xAdvance;
      
              fontAtlas.addLetterDefinitions(fontDef, letter);
            }
      
            bf['_fontDefDictionary'] = fontAtlas;
            node.getComponent(cc.Label).font = bf;
          }
        }
      }
      
  1. 文章总结

BMFont,Skeleton 这一类都是cocos creator需要同时加载多个文件才可以正常运行的组件。以下附上远程加载骨骼动画的方法。

const assetRes = {
  image: null, // 存储图片资源
  ske: null, // 存储骨骼动画资源
  atlas: null, // 存储 atlas 资源
};
const urlArray = url.split('/');

const fileName = urlArray[urlArray.length - 1];

const resUrl = url + '/' + fileName;

assetRes.image = await getResource(resUrl + '.png'); // 加载图片资源
assetRes.ske = await getResource(resUrl + '.json'); // 加载骨骼动画资源
assetRes.atlas = await getResource(resUrl + '.atlas'); // 加载 atlas 资源

// 判断节点是否有骨骼
const skeletonData = new sp.SkeletonData(); // 创建骨骼数据对象
skeletonData.skeletonJson = assetRes.ske.json; // 装载骨骼动画数据
skeletonData.atlasText = assetRes.atlas.text; // 装载 atlas 数据
skeletonData.textures = [assetRes.image]; // 加载图片
skeletonData.textureNames = [fileName + '.png'];
let skeletonComponent = node.getComponent(sp.Skeleton);
if (!skeletonComponent) {
  skeletonComponent = node.addComponent(sp.Skeleton);
}

skeletonComponent.skeletonData = skeletonData;
skeletonComponent.setSkin('default');
skeletonComponent.setAnimation(0, 'animation', true);