Laya 优化Spine渲染性能16倍

Spine

Description
Spine is more powerful than Dragonbones, with various output formats such as IK, FFD, mesh Meshes, Bounding Boxes
Spine is smaller than frame animation, with relatively lower art cost and less work

Spine Tool Class
Copy it into your project.

    export class SpineFactory {

        /** 版本号 */
        protected static version: Laya.SpineVersion;
        /** 缓存池 */
        protected static cachePool: { [url: string]: Laya.SpineTemplet } = {};
        /** 加载完成事件 */
        protected static loadedCallback: Map<Laya.SpineTemplet, Laya.Handler[]> = new Map<Laya.SpineTemplet, Laya.Handler[]>();

        /**
         * 初始化
         * @param ver Spine版本号
         */
        public static init(ver: Laya.SpineVersion) {
            SpineFactory.version = ver;
        }

        /**
         * 提前预加载
         * @param url .skel文件url
         * @param cb 加载完成回调
         */
        public static load(url: string, cb: Laya.Handler) {
            SpineFactory.loads([url], cb);
        }

        /**
         * 提前预加载
         * @param urls  Array<.skel>
         * @param cb 加载完成回调
         */
        public static loads(urls: string[], cb: Laya.Handler) {
            for (let i = 0; i < urls.length; i++) {
                let url = urls[i];
                if (!SpineFactory.cachePool[url]) {
                    let st = SpineFactory.cachePool[url] = new Laya.SpineTemplet(SpineFactory.version);
                    (i == urls.length - 1) && SpineFactory.bindLoadedCallback(st, cb);
                    st.on(Laya.Event.COMPLETE, SpineFactory, SpineFactory.loadComplete);
                    st.on(Laya.Event.ERROR, SpineFactory, SpineFactory.loadFail);
                    st.loadAni(url);
                }
                else if (!SpineFactory.cachePool[url]['__loaded']) {
                    SpineFactory.bindLoadedCallback(SpineFactory.cachePool[url], cb);
                }
                else {
                    cb && cb.runWith(SpineFactory.cachePool[url]);
                }
            }
        }

        /** 添加 加载结束回调 */
        private static bindLoadedCallback(st: Laya.SpineTemplet, cb: Laya.Handler) {
            let cbs = SpineFactory.loadedCallback.get(st);
            if (!cbs) {
                cbs = [];
            }
            cbs.push(cb);
            SpineFactory.loadedCallback.set(st, cbs);
        }

        /** 加载完成 */
        protected static loadComplete(obj) {
            obj['__loaded'] = true;
            let cbs = SpineFactory.loadedCallback.get(obj);
            cbs && [].forEach.call(cbs, cb => {
                cb && cb.runWith(obj);
            });
        }

        /** 加载失败 */
        protected static loadFail(e) {
            console.error(e);
        }

        /**
         * 生成新的龙骨
         * @param in_url 龙骨url
         * @param out_res 加载完成后的回调
         */
        public static spawn(in_url: string, out_res: (spine: Laya.SpineSkeleton) => void): void {
            if (SpineFactory.cachePool[in_url] && SpineFactory.cachePool[in_url]['__loaded']) {
                out_res(SpineFactory.cachePool[in_url].buildArmature());
            }
            else {
                SpineFactory.load(in_url, Laya.Handler.create(this, (st: Laya.SpineTemplet) => {
                    out_res(st.buildArmature());
                }));
            }
        }

        /**
         * 添加一个动画播放停止的事件监听 
         * @param spine 
         * @param handler 
         * @param once 
         */
        public static AddCompleteHandle(spine: Laya.SpineSkeleton, caller: any, func: Function, once = false) {

            if (once) {

                spine.once(Laya.Event.STOPPED, caller, func);
            } else {

                spine.on(Laya.Event.STOPPED, caller, func);
            }
        }

        /**
         * 移除Spine动画 停止事件监听
         * 
         * @param spine 指定的Laya.SpineSkeleton实例
         * @param caller 如果 caller 和 func 都存在 则指定删除,如果仅有caller,则移除spine上所有关于caller的监听
         * @param func 仅配合caller使用 指定删除某对象某一方法
         */
        public static RemoveCompleteHandle(spine: Laya.SpineSkeleton, caller?: any, func?: Function) {
            if (caller && func) {
                spine.off(Laya.Event.STOPPED, caller, func);
            }
            else if (caller) {
                spine.offAllCaller(caller);
            }
            else {
                spine.offAll(Laya.Event.STOPPED);
            }
        }
    }

Init

SpineFactory.init(Laya.SpineVersion.v4_0); //项目初始化设置你的spine文件版本

Example: create a spine

 SpineFactory.spawn("res/spine/ufo.skel", spine => {
                //this.ufoSpine = spine; //缓存对象
                this.sprite.addChild(spine); //添加到舞台
                spine.x = 21;	//设置位置
                spine.y = 56;
				
				spine.play("fly", false); //播放动画,不循环
				//添加动画结束事件
				SpineFactory.AddCompleteHandle(spine,this,()=>{
					spine.destroy(true);//动画结束 销毁spine
				},true);
            });

Example: preload

//提前加载一个spine
SpineFactory.load("res/spine/ufo.skel", null);

//提前加载多个
SpineFactory.loads([
            "res/spine/avatar_alice.skel",
            "res/spine/avatar_elena.skel",
            "res/spine/avatar_ethan.skel"
        ], Laya.Handler.create(this, () => {

            //TODO: 所有spine加载完成后 回调处理
            
        }));

//使用. 内部检测是否已经加载缓存
SpineFactory.spawn("res/spine/avatar_alice.skel",spine=>{

});

Example: add frame event


//封装一个Spine外壳
class SpineHelper extends Laya.EventDispatcher {
	//维护SpineSkeleton
	private spineInst:Laya.SpineSkeleton;
	//获取spine实例
	public get spine(){
		return this.spineInst;
	}
	//是否加载完成
	public get loaded(){
		return this.spineInst != null;
	}
	
	//spineUrl 文件地址: "res/spine/avatar_alice.skel"
	//out_spineCreatedFn 生成后的回调: Laya.Handler
	constructor( spineUrl:string, out_spineCreatedFn:Laya.Handler ){
		super();
		
		SpineFactory.spawn(spineUrl,spine=>{
			//监听LABEL事件。该事件会抛出当前动画出发的事件帧名称
			//当有事件帧被被触发时 会派发LABEL事件 可以通过e.name来获取帧事件名称
			spine.on(Laya.Event.LABEL, this, this.onEvent);
			this.spineInst = spine;
			out_spineCreatedFn.runWith(spine);
		});
	}
	onEvent(e){
		 this.event(e.name);
	}
}

Example: Listening for Spine events
Add events to the Spine editor
在这里插入图片描述
The code listens to and handles events

	let ufo = new SpineHelper("res/spine/ufo.skel",Laya.Handler.create(this,(spine:Laya.SpineSkeleton)=>{
		
		//TODO生成后 需要干的事
		
	}));
	
	//监听事件. 和 Laya.EventDispatcher 用法一致
	ufo.on("chuxian",this,this.show);
	//监听一次事件 结束后自动移除 
	ufo.once("xiaoshi",this,this.hide);
	

Optimization of Spine Performance

经测试 场景中超过10个Spine同时播放 Android低端机型及ios14,15 就会存在卡顿情况
避免这类情况的一个方案可以关闭 抗锯齿 在ios上能得到很好的改善
!!!Laya官方给的解释是 Spine库的问题。所有Spine均有此问题 所以想要尝试 降版本 或者 想转成.sk格式的 同学 请停止你的威胁行为
另外 在处理Spine的时候 一定不要一直挂在节点上 而是需要时 再挂到场景中 不需要时则隐藏
当然 如果这个Spine一直需要保持存在的话 就另当别论了

下载优化后的 spine库文件 可以有效提升16倍spine渲染性能
https://download.csdn.net/download/qq_39162566/86248577

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客柒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值