版本:2.4.10

参考:卡顿优化之卡顿原理全解析与如何快速定位到卡顿问题

 

一 为啥要分帧

一个游戏帧率是60时,每帧分配的执行时间是1秒/60 = 0.016666秒 = 16毫秒。

当这一帧的计算渲染消耗时间超过16毫秒时,就会进行扩帧,例如计算耗时需要50毫秒,那么需要至少4帧进行计算,导致4帧停留在同一个画面上,视觉上游戏就卡顿了。

 

 

为了防止卡顿,所以把大量计算分帧执行,例如总耗时需要50毫秒的计算,分到10帧去执行,那么每帧只占用5毫秒的时间,那么就不会导致卡顿。

 

二 分帧函数

首先获取当前时间,然后执行函数,再次获取当前时间,如果两次时间超过了分配的执行时间,则将函数放到下一帧执行。

FrameExecute.ts:

/**
 * 分帧执行
 * @author chenkai 2022.9.1
 */
export class FrameExecute extends cc.Component {

    //单例
    private static _instance: FrameExecute;
    public static get ins() {
        if (this._instance == null) {
            this._instance = new FrameExecute();
        }
        return this._instance;
    }

    /**
     * 分帧执行
     * @param fun     执行函数
     * @param target  执行函数对象
     * @param start   起始次数     (从0开始,0表示执行第1次)
     * @param max     最大执行次数 (例如5则表示函数总共执行5次)
     * @param executeTime   分配的执行时间
     * @param data    传递数据
     * @returns
     */
    public execute(fun: Function, target: any, start: number, max: number, executeTime: number, data: any = null) {
        //获取开始时间
        var startTime = new Date().getTime();
        //执行计数
        var count = start;
        //开始执行函数,如果超过分配的执行时间,则延迟到下一帧执行
        for (var i = count; i < max; i++) {
            //执行函数
            fun.call(target, count, data);
            //超过最大执行次数,则退出
            count++;
            if (count >= max) {
                return;
            }
            //获取消耗时间
            var costTime = new Date().getTime() - startTime;
            console.log("执行耗时:", costTime);
            //消耗时间 > 分配的时间,则延迟到下一帧执行
            if (costTime > executeTime) {
                console.log("超时,进入下一轮加载")
                this.scheduleOnce(() => { this.execute(fun, target, count, max, executeTime, data) });
                return;
            }
        }
    }
}

  

在场景中使用,分帧加载一个物品并显示到场景中

MainScene.ts:

const { ccclass, property } = cc._decorator;

/**
 * 分帧测试
 * @author chenkai 2022.9.1
 */
@ccclass
export default class FrameLoad extends cc.Component {

    @property({ type: cc.Node, tooltip: "item容器" })
    content: cc.Node = null;

    @property({ type: cc.Node, tooltip: "item" })
    item: cc.Node = null


    onLoad() {
        this.content.removeAllChildren();
        FrameExecute.ins.execute(this.loadAsset, this, 0, 50, 1, { name: "数据" });
    }

    /**
     * 加载函数
     * @param count 执行次数
     * @param data  传递数据
     */
    public loadAsset(count, data) {
        console.log("执行第n次:", count, data);
        var item = cc.instantiate(this.item);
        item.parent = this.content;
    }
}

 

显示效果

 

 

 

 

 

 

 

 

 

posted on 2022-09-01 12:01  gamedaybyday  阅读(1092)  评论(0编辑  收藏  举报