zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    [CF603C] Lieges of Legendre
    [CF1070A] Find a Number
    [CF431D] Random Task
    2020牛客暑期多校训练营(第二场)C
    2020牛客暑期多校训练营(第二场)F
    2020牛客暑期多校训练营(第二场)D
    2020牛客暑期多校训练营(第一场)H
    [CF1000E] We Need More Bosses
    Java学习2 (ThreadLocal)
    Java复习1
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/11832069.html
Copyright © 2011-2022 走看看