CocosCreator 源码​cocos2d/core/utils/profiler/CCProfiler.js详解

var macro = require('../../platform/CCMacro');

const PerfCounter = require('./perf-counter');

/* 是否展示FPS变量 */
let _showFPS = false;
/* 字体大小15 */
let _fontSize = 15;

let _stats = null;
let _rootNode = null;
let _label = null;

function generateStats() {
    if (_stats) return;

    _stats = {

        /* 每帧的时间;如果你游戏帧率是60fps,,则每帧时间为1/60=0.01666,就是16ms; */
        frame: { desc: 'Frame time (ms)', min: 0, max: 50, average: 500, color: '#FF0' },
        /* Framerate(FPS): 帧率是以帧称为单位的位图图像连续出现在显示器上的频率,物质在1s内完成周期性变化的次数叫做频率,常用f表示 f=1/T;
                一秒展示次数越多,看起来越流畅 */
        fps: { desc: 'Framerate (FPS)', below: 30, average: 500, color: '#000' },
        /* 
        是一种行为(指令),即 CPU 调用图形 API,命令 GPU 进行图形绘制,可以了理解为渲染调用次数;详细可以参考https://www.jianshu.com/p/c0f4598cbb20
         */
        draws: { desc: 'Draw call', color: '#000' },
        /* 游戏逻辑耗时 */
        logic: { desc: 'Game Logic (ms)', min: 0, max: 50, average: 500, color: '#000' },
        /* 渲染耗时 */
        render: { desc: 'Renderer (ms)', min: 0, max: 50, average: 500, color: '#000' },
        /* 渲染方式:webgl或者canvas */
        mode: { desc: cc.game.renderType === cc.game.RENDER_TYPE_WEBGL ? 'WebGL' : 'Canvas', min: 1 }
    };

    let now = performance.now();
    /* performance.now() 返回的时间戳以毫秒为单位,通常具有微秒级或纳秒级的精确度。它可以用于测量非常小的时间间隔,帮助我们了解代码的性能和优化需求
 */
    for (let id in _stats) {
        _stats[id]._counter = new PerfCounter(id, _stats[id], now);
    }
}

function generateNode() {
    /* 假如已经存在rootnode,则返回 */
    if (_rootNode && _rootNode.isValid) return;


    /* 展示监控信息的总node */
    _rootNode = new cc.Node('PROFILER-NODE');
    _rootNode.x = _rootNode.y = 10;

    //枚举数值31
    // 节点的分组索引
    _rootNode.groupIndex = cc.Node.BuiltinGroupIndex.DEBUG;
    cc.Camera._setupDebugCamera();

    _rootNode.zIndex = macro.MAX_ZINDEX;//Math.pow(2, 15) - 1,
    /* 常驻根节点,不会被销毁 */
    cc.game.addPersistRootNode(_rootNode);

    /* 创建左侧node */
    let left = new cc.Node('LEFT-PANEL');
    /* 锚点0,0 */
    left.anchorX = left.anchorY = 0;
    /* 添加label的component, */
    let leftLabel = left.addComponent(cc.Label);
    /* 设置字体大小 */
    leftLabel.fontSize = _fontSize;
    /* 行间距 */
    leftLabel.lineHeight = _fontSize;
    /* 设置父节点,addchild结果一样 */
    left.parent = _rootNode;

    /* 创建右侧node */
    let right = new cc.Node('RIGHT-PANEL');
    right.anchorX = 1;
    right.anchorY = 0;
    right.x = 200;
    let rightLabel = right.addComponent(cc.Label);
    rightLabel.horizontalAlign = cc.Label.HorizontalAlign.RIGHT;
    rightLabel.fontSize = _fontSize;
    rightLabel.lineHeight = _fontSize;
    right.parent = _rootNode;

    /* 当平台信息不是百度和微信,把左右侧label的模式设置为char模式 */
    if (cc.sys.platform !== cc.sys.BAIDU_GAME_SUB &&
        cc.sys.platform !== cc.sys.WECHAT_GAME_SUB) {
        leftLabel.cacheMode = cc.Label.CacheMode.CHAR;
        rightLabel.cacheMode = cc.Label.CacheMode.CHAR;
    }

    _label = {
        left: leftLabel,
        right: rightLabel
    };
}

function beforeUpdate() {
    generateNode();//update之前判断根节点是否已有

    let now = cc.director._lastUpdate;
    /* 帧率和逻辑开启计时 */
    _stats['frame']._counter.start(now);
    _stats['logic']._counter.start(now);
}

function afterUpdate() {
    let now = performance.now();
    if (cc.director.isPaused()) {
        /* 暂停了,counter 重置 */
        _stats['frame']._counter.start(now);
    }
    else {
        /* 添加时间样本 */
        _stats['logic']._counter.end(now);
    }
    _stats['render']._counter.start(now);
}

/* 没搜到有调用这个方法, */
function updateLabel(stat) {
    let length = 20;
    let desc = stat.desc;
    let value = stat._counter.human() + '';
    stat.label.string = stat.desc + '  ' + stat._counter.human();
}

/* 这是个监听回调函数,在releaseManager的tryRelease 和 CCGame的restart都有调用,
这两个变化,主要是在于场景更新后,这些属性要及时更新 */
function afterDraw() {
    /* 渲染后 */
    let now = performance.now();
    _stats['render']._counter.end(now);
    _stats['draws']._counter.value = cc.renderer.drawCalls;
    _stats['frame']._counter.end(now);
    _stats['fps']._counter.frame(now);

    let left = '';
    let right = '';
    /* 遍历object属性 */
    for (let id in _stats) {
        let stat = _stats[id];//获取一个object,
        stat._counter.sample(now);//计算平均值

        left += stat.desc + '\n';
        right += stat._counter.human() + '\n';
    }

    /* 对象下的两个label,设置string 和颜色更新 */
    if (_label) {
        _label.left.string = left;
        _label.left.node.color = new cc.Color(255, 0, 0);//red
        _label.right.string = right;
        _label.right.node.color = new cc.Color(255, 255, 0);//yellow
    }
}

cc.profiler = module.exports = {
    /* 判断当前状态是否是展示的 */
    isShowingStats() {
        return _showFPS;
    },

    hideStats() {
        /* 关闭性能参数的展示,设置为隐藏,去掉监听 */
        if (_showFPS) {
            if (_rootNode) {
                _rootNode.active = false;
            }
            /* 去掉三个监听 */
            cc.director.off(cc.Director.EVENT_BEFORE_UPDATE, beforeUpdate);
            cc.director.off(cc.Director.EVENT_AFTER_UPDATE, afterUpdate);
            cc.director.off(cc.Director.EVENT_AFTER_DRAW, afterDraw);
            _showFPS = false;
        }
    },

    /* 展示性能label,添加监听 */
    showStats() {
        if (!_showFPS) {
            generateStats();

            if (_rootNode) {
                _rootNode.active = true;
            }
            /* 添加三个监听行数 */
            cc.director.on(cc.Director.EVENT_BEFORE_UPDATE, beforeUpdate);

            /* 导演类CCDirector 执行mainloop后,调用 */
            cc.director.on(cc.Director.EVENT_AFTER_UPDATE, afterUpdate);
            /* /* 这是个监听回调函数,在releaseManager的tryRelease 和 CCGame的restart都有调用,
这两个变化,主要是在于场景更新后,这些属性要及时更新 */ */
            cc.director.on(cc.Director.EVENT_AFTER_DRAW, afterDraw);
            _showFPS = true;
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值