Egret自定义位图文字(自定义+BitmapLabel)
一 自定位图文字
因为egret的位图文字是texturemerger做的,需要多张单图片导入tm,然后导出两个文件来使用,过程比较麻烦。

而Laya的位图文字则是一张整图数字图片,使用FontClip就能直接使用, 很方便。
所以现在弄个自定义的位图文字类,也不用tm去导图了。
二 决战沙城的位图文字代码
先来看看别人的。据说这个框架里的位图文字被用于很多大型H5 mmo项目。14年写的工具类ε=(´ο`*)))唉。
主要原理就是1个字1个bitmap,然后并列排起来。“123“就是3个bitmap排起来。
/**
* 素材需要提前加载好
* 素材命名规则:类型_数值(有类型是因为一般会同时有几种数字图片,比如大小号或不同颜色)
* 点号素材命名:类型_dot
* 创建BitmapNumber使用createNumPic返回DisplayObjectContainer
* 创建好的BitmapNumber数值需要变化是调用changeNum
* 回收使用desstroyNumPic
*
* Created by Saco on 2014/8/1.
*/
class BitmapNumber extends SingtonClass {
private _imgPool:egret.Bitmap[];
private _containerPool:egret.DisplayObjectContainer[]; public constructor() {
super();
this._imgPool = [];
this._containerPool = [];
} /*
* 根据需要的数字和类型返回一个DisplayObjectContainer
* num数字值,支持小数点
* type素材类型
* */
public createNumPic(num:number, type:string):egret.DisplayObjectContainer {
var container:egret.DisplayObjectContainer = this.getContainer();
var numStr:string = num.toString();
var index:number = 0;
var tempBm:egret.Bitmap;
for (index; index < numStr.length; index++) {
tempBm = this.getSingleNumPic(numStr.charAt(index), type);
container.addChild(tempBm);
}
this.repositionNumPic(container);
return container;
} //回收带数字的DisplayObjectContainer
public desstroyNumPic(picContainer:egret.DisplayObjectContainer):void {
this.clearContainer(picContainer);
if (picContainer.parent)
picContainer.parent.removeChild(picContainer);
this._containerPool.push(picContainer);
} /*
* 改变带数字的DisplayObjectContainer数字值
* 提供这个方法是为了提高效率,直接更换之前创建对象的texture,避免多余的删除和创建
* */
public changeNum(picContainer:egret.DisplayObjectContainer, num:number, type:string):void {
var numStr:string = num.toString();
var tempBm:egret.Bitmap;
//如果当前数字个数多于目标个数则把多余的回收
if (picContainer.numChildren > numStr.length) {
while (picContainer.numChildren > numStr.length) {
this.recycleBM(<egret.Bitmap>picContainer.getChildAt(picContainer.numChildren - 1))
}
}
var index:number = 0;
var tempStr:string;
for (index; index < numStr.length; index++) {
//如果当前的Bitmap数量不够则获取新的Bitmap补齐
if (index >= picContainer.numChildren)
picContainer.addChild(this.getBitmap());
tempStr = numStr.charAt(index);
tempStr = tempStr == "." ? "dot" : tempStr;
(<egret.Bitmap>picContainer.getChildAt(index)).texture = this.getTexture(tempStr, type);
}
this.repositionNumPic(picContainer);
} //每个数字宽度不一样,所以重新排列
private repositionNumPic(container:egret.DisplayObjectContainer):void {
var index:number = 0;
var lastX:number = 0;
var temp:egret.DisplayObject;
for (index; index < container.numChildren; index++) {
temp = container.getChildAt(index);
temp.x = lastX;
lastX = temp.x + temp.width;
}
} //清理容器
private clearContainer(picContainer:egret.DisplayObjectContainer):void {
while (picContainer.numChildren) {
this.recycleBM(<egret.Bitmap>picContainer.removeChildAt(0));
}
} //回收Bitmap
private recycleBM(bm:egret.Bitmap):void {
if (bm && bm.parent) {
bm.parent.removeChild(bm);
bm.texture = null;
this._imgPool.push(bm);
}
} private getContainer():egret.DisplayObjectContainer {
if (this._containerPool.length)
return this._containerPool.shift();
return new egret.DisplayObjectContainer();
} //获得单个数字Bitmap
private getSingleNumPic(num:string, type:string):egret.Bitmap {
if (num == ".")
num = "dot";
var bm:egret.Bitmap = this.getBitmap();
bm.texture = this.getTexture(num, type);
return bm;
} private getTexture(num:string, type:string):egret.Texture {
return RES.getRes(type + num);
} private getBitmap():egret.Bitmap {
if (this._imgPool.length)
return this._imgPool.shift();
return new egret.Bitmap();
}
}
顺便看了下凡人修仙传的位图文字。可以看到文字是一整张合图且无序排列,而且network里没有fnt文件。推测应该也是使用支持单张数字的自定义位图文字。

三 我自己写了个
相对于决战沙城的有些改动
1. 支持使用整图和单张图片。
2. 支持代码创建和拖动到exml上摆放。
3. 文字图片可以使用tm和其他图片进行合并,减少drawcall和http请求,而不影响位图文字的使用。
需要注意的是
1. 不要用cacheAsBitmap,对于变化数字非常卡。我试了下,卡爆了。
测试用整图

测试用单张图

具体代码
/**
* 位图文字
* @deprecated 可以使用单张整图或者多张散图,制作位图文字。
* 注意"."的图片命名要改为dot,例如"1"是font_1.png,那么"."的图片命名是font_dot.png。
* @author ck 2019.11.10
*/
class BitmapFont extends eui.Component{
/**位图缓存 */
private static bmCaches:Array<egret.Bitmap> = [];
/**纹理缓存 */
private static textureCaches = {};
/**显示的文字 */
private _text:string;
/**图片名 */
private pngName:string; public constructor() {
super();
} /**
* 文字在一张图上
* @param pngName 图片名 pngName = font_test (font_test.png)
* @param txt 文字名 "0123456789.+-"
*/
public static registerByOne(pngName:string, txt:string){
let textureCache = this.getTextureCache(pngName);
if(textureCache.length > 0){
console.log("位图字体缓存已存在:",pngName);
return;
}
let src:egret.Texture = new egret.Texture();
src = RES.getRes(pngName + "_png");
let len = txt.length;
let fontWidth:number = src.textureWidth/len;
let fontHeight:number= src.textureHeight;
let texture:egret.Texture;
let rect:egret.Rectangle = new egret.Rectangle();
for(let i=0;i<len;i++){
texture = new egret.Texture();
texture.disposeBitmapData = false;
texture.$bitmapData = src.$bitmapData
texture.$initData(i*fontWidth,0, fontWidth, fontHeight, 0, 0, fontWidth, fontHeight, src.textureWidth, src.textureHeight);
textureCache[txt.charAt(i)] = texture;
}
} /**
* 文字在不同的图片上
* @param pngName 图片名 pngName=font_test 多张图片源文件名(font_test0.png font_test1.png .... font_testdot.png)
* @param txt 文字名 "0123456789.+-"
*/
public static registerByMulti(pngName:string, txt:string){
let textureCache = this.getTextureCache(pngName);
if(textureCache.length > 0){
console.log("位图字体缓存已存在:",pngName);
return;
}
let len = txt.length;
let char:string;
for(let i=0;i<len;i++){
char = txt.charAt(i);
if(char == "."){
textureCache[char] = RES.getRes(pngName + "dot" + "_png");
}else{
textureCache[char] = RES.getRes(pngName + char + "_png");
}
}
} /**
* 获取纹理缓存
* @param pngName 图片名
*/
public static getTextureCache(pngName:string){
let textureCache = BitmapFont.textureCaches[pngName];
if(textureCache == null){
textureCache = [];
BitmapFont.textureCaches[pngName] = textureCache;
}
return textureCache;
} /**
* 设置文字
* @param txt 文字
*/
public set text(txt:string){
let bmCaches = BitmapFont.bmCaches;
let textureCache = BitmapFont.getTextureCache(this.pngName);
let curLen = this.numChildren;
let targetLen = txt.length; this._text = txt; //文字存在,且大于显示文字,则移除多余文字
if(curLen > targetLen){
let bm:egret.Bitmap;
for(let i=curLen-1;i>=targetLen;i--){
bm = this.removeChildAt(i) as egret.Bitmap;
bm.texture = null;
bmCaches.push(bm);
}
}
//显示文字
let bm:egret.Bitmap;
let tempX:number = 0;
let char:string;
for(let i=0;i<targetLen;i++){
//少于显示文字,则增加文字
if(i >= curLen){
if(bmCaches.length > 0){
bm = bmCaches.pop();
}else{
bm = new egret.Bitmap();
}
this.addChild(bm);
}
bm = this.getChildAt(i) as egret.Bitmap;
bm.texture = textureCache[txt.charAt(i)];
bm.x = tempX;
tempX = bm.x + bm.width;
}
} /**
* 获取文字
*/
public get text(){
return this._text;
} /**
* 设置文字类型
* @value 字体类型 文字是font_test.png一张图片,则value = "font_test""。 若文字是font_test0.png font1_test1.png..多张图片,则value="font_test"
*/
public set font(value:string){
this.pngName = value;
} /**销毁 */
public destroy(){
//回收bitmap
let len = this.numChildren;
let bm:egret.Bitmap;
let bmCaches = BitmapFont.bmCaches;
for(let i=len-1;i>=0;i--){
bm = this.getChildAt(i) as egret.Bitmap;
this.removeChild(bm);
bm.texture = null;
bmCaches.push(bm);
}
//从视图移除
this.parent && this.parent.removeChild(this);
}
}
使用示例
//注册
BitmapFont.registerByOne("font_test","02345"); //使用
let mc:BitmapFont = new BitmapFont();
mc.font = "font_test";
mc.text = "0222";
this.addChild(mc);
运行效果

四 测试下效率
新建n个位图文字放到列表bmList,然后不停的切换数字显示
private onEnterFrame(){
for(let i=0;i<this.bmList.length;i++){
//BitmapNumber.ins().changeNum(this.bmList[i],(Math.random()>0.5)?200000:200,"font" );
this.bmList[i].text = (Math.random()>0.5)?"200000":"200";
}
}
200个 1000个 2000个 4000个
自定义字体 60FPS 58-60FPS 30FPS 8FPS
BtimapLabl 60FPS 59-60FPS 59-60FPS 30FPS
决战沙城 60FPS 59-60FPS 24FPS 8FPS
Egret自定义位图文字(自定义+BitmapLabel)的更多相关文章
- Android实现自定义带文字和图片的Button
Android实现自定义带文字和图片的Button 在Android开发中经常会需要用到带文字和图片的button,下面来讲解一下常用的实现办法. 一.用系统自带的Button实现 最简单的一种办法就 ...
- WPF自定义空心文字
首先创建一个自定义控件,继承自FrameworkElement,“Generic.xaml”中可以不添加样式. 要自定义空心文字,要用到绘制格式化文本FormattedText类.FormattedT ...
- Android之自定义画图文字动画
结构: BaseView: package com.caiduping.canvas; import android.content.Context; import android.graphics. ...
- oracle的order by decode根据文字自定义排序的例子
oracle的order by decode根据文字自定义排序的例子: order by decode(t.title, '当前生效预警', 1, '今日即将生效', 2, '明日预计生效', 3, ...
- 写了一个迷你toast提示插件,支持自定义提示文字和显示时间
写了一个迷你toast提示插件,支持自定义提示文字和显示时间,不想用其他第三方的ui插件,又想要toast等小效果来完善交互的同学可以试试, 代码中还贡献了一段css能力检测js工具函数,做项目的时候 ...
- Laya的位图文字
参考: Laya文本 测试版本:Laya 2.1.1.1 大部分游戏都会用到位图文字,例如dnf的伤害数字. 白鹭的位图文字是美术提供0-9十张单张图片,由TextureMerger导出fnt+jso ...
- Dialog详解(包括进度条、PopupWindow、自定义view、自定义样式的对话框)
Dialog详解(包括进度条.PopupWindow.自定义view.自定义样式的对话框) Android中提供了多种对话框,在实际应用中我们可能会需要修改这些已有的对话框.本实例就是从实际出发, ...
- asp.net MVC 自定义@helper 和自定义函数@functions小结
asp.net Razor 视图具有.cshtml后缀,可以轻松的实现c#代码和html标签的切换,大大提升了我们的开发效率.但是Razor语法还是有一些棉花糖值得我们了解一下,可以更加强劲的提升我们 ...
- activiti自定义流程之自定义表单(三):表单列表及预览和删除
注:(1)环境配置:activiti自定义流程之自定义表单(一):环境配置 (2)创建表单:activiti自定义流程之自定义表单(二):创建表单 自定义表单创建成功,要拿到activiti中使用,自 ...
随机推荐
- 20180520模拟赛T1——math
[问题描述] 小美有 n 个点 m 条边. 让你给每个点一个正整数编号. 每条边有两个属性,相连的两个点的编号的 GCD 和 LCM. 题目保证整张图连通. 让你构造出一个编号. [输入格式] 从文件 ...
- 25、typing导入Python的数据类型模块、collections集合模块
一.typing模块 1.typing模块的作用 类型检查,防止运行时出现参数和返回值类型不符合. 作为开发文档附加说明,方便使用者调用时传入和返回参数类型. 该模块加入后并不会影响程序的运行,不会报 ...
- Collections.synchronizedList使用
1.SynchronizedList类具体代码: static class SynchronizedList<E> extends SynchronizedCollection<E& ...
- ES6学习笔记--Object.is()
ES5比较两个值是否相等, 相等运算符(==)和恒等运算符(===).它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0. javascript缺乏一种运算,在所有环境中, ...
- 014_matlab读取ecxel(直接导入)
视频教程:https://v.qq.com/x/page/c3039b5htwx.html 资料下载:https://download.csdn.net/download/xiaoguoge11/12 ...
- Numpy | 06 从已有的数组创建数组
numpy.asarray numpy.asarray 类似 numpy.array,但 numpy.asarray 参数只有三个,比 numpy.array 少两个. numpy.asarray(a ...
- 使用Map文件查找崩溃信息
简介 编写整洁的应用程序是一回事.但是当用户告诉你你的软件已经崩溃时,你知道在添加其他功能之前最好先解决这个问题.如果你够幸运的话,用户会有一个崩溃地址.这将大大有助于解决这个问题.但是你怎么能用这个 ...
- 小功能 清单模板导入 根据Excel生成树
把代码备份一下,免得硬盘又坏了,看来已经造成心理阴影了啊. 方式一: //清单范本 public void test1() { //生成说明 var ds = ExcelHelper.ExcelToD ...
- Navicat配置跳板机连接数据库
需求 在开发中,有时候我们会碰到这么一个情况.数据库的服务器在内网,如果想连接,必须得先ssh登陆到跳板机,然后在跳板机ssh到达数据库所在服务器,进而操作数据库.遗憾的是,如果跳板机和数据库所在服务 ...
- OpenFOAM——设置非均匀边界方法总结
在使用OpenFOAM求解的时候我们经常需要设置非均匀的边界,比如我们在计算层流的时候,很多时候需要入口为充分发展的入口边界,下面我们就以入口处为充分发展的层流速度分布为总结OpenFOAM当中设定不 ...