coco2d-x-html5之Director解析

上一講我們講了爲什麼調用了cc.game.run後,會執行cc.game.onStart函數。這一講,我們通過分析一下 CCDirector.js的代碼,來了解一下游戲是怎麼渲染的。

上一講中,我們看到,在cc.game.prepare方法裏面,在加載引擎代之後,執行了 cc.game._setAnimFrame()和cc.game._runMainLoop()。
在這裏插入圖片描述

接下來我們看下這兩個函數到底做了什麼。

    //  @Time ticker section
    // 設置幀率
    _setAnimFrame: function () {
        // 預計下一幀執行後的時間
        this._lastTime = new Date();
        // 幀率
        var frameRate = cc.game.config[cc.game.CONFIG_KEY.frameRate];
        // 每幀的時間
        this._frameTime = 1000 / frameRate;
        // 如果幀率不是60或30的時候,使用window.setTimeout來控制執行頻率
        if (frameRate !== 60 && frameRate !== 30) {
            window.requestAnimFrame = this._stTime;
            window.cancelAnimationFrame = this._ctTime;
        } else {
            // 60或者30幀的時候,使用默認的,30時通過 skip 跳過一幀的方式
            // 使用默認比setTimeout速度快
            // 疑問 不是30幀的時候,爲什麼不使用跳過的方式來實現?
            window.requestAnimFrame = window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                window.oRequestAnimationFrame ||
                window.msRequestAnimationFrame ||
                this._stTime;
            window.cancelAnimationFrame = window.cancelAnimationFrame ||
                window.cancelRequestAnimationFrame ||
                window.msCancelRequestAnimationFrame ||
                window.mozCancelRequestAnimationFrame ||
                window.oCancelRequestAnimationFrame ||
                window.webkitCancelRequestAnimationFrame ||
                window.msCancelAnimationFrame ||
                window.mozCancelAnimationFrame ||
                window.webkitCancelAnimationFrame ||
                window.oCancelAnimationFrame ||
                this._ctTime;
        }
    },
    
    // 定時函數
    _stTime: function (callback) {
        // 當前時間戳
        var currTime = new Date().getTime();
        // cc.game._fameTime 值爲 1000 / 幀率 單位爲毫秒
        // cc.game._lastTime 值爲上次預計 執行到這裏的時間戳

        // timeToCall下次執行callback間隔時間,正常時每幀的時間cc.game._frameTime
        // currTime-cc.game._lastTime 就是預計和實際時間的差值
        // 如果性能不好,currTime - cc.game._lastTime大於0,那下一幀的時間就要少一些
        var timeToCall = Math.max(0, cc.game._frameTime - (currTime - cc.game._lastTime));
        var id = window.setTimeout(function () {
                callback();
            },
            timeToCall);
        // 下一幀執行的預計時間,如果性能好的話,下次執行到_stTime函數時,這個值等你
        cc.game._lastTime = currTime + timeToCall;
        return id;
    }, 
    // 取消定時
    _ctTime: function (id) {
        window.clearTimeout(id);
    },

通過上面的代碼我們可以看到,如果幀率爲60或30的時候,使用window.requestAnimationFrame的方式來定時執行函數。其他值時,使用window.setTimeout來實現。其中使用window.setTimeout的時候,通過記錄預計下次執行的時間 cc.game._lastTime的值,來動態計算下次執行 回調的時間。

接下來看下

    // 運行主循環
    _runMainLoop: function () {
        var self = this,
            callback, config = self.config,
            // projection.json的值
            CONFIG_KEY = self.CONFIG_KEY,
            // 導演
            director = cc.director,
            // 是否跳過渲染。幀率爲30幀的時候 用
            skip = true,
            // 幀率
            frameRate = config[CONFIG_KEY.frameRate];

        // 設置FPS顯示狀態 爲true的時候,左下角顯示幀率等信息
        director.setDisplayStats(config[CONFIG_KEY.showFPS]);

        // 每幀回調的函數
        callback = function () {
            // 沒有暫停的時候,繼續執行
            if (!self._paused) {
                // 如果幀率是30
                if (frameRate === 30) {
                    // 因爲 幀率是30和60的時候,調用的是window.requestAnimationFrame,默認是60幀 (原因見cc.game._setAnimFrame方法)
                    // 所以每隔一幀跳過不執行
                    if (skip = !skip) {
                        self._intervalId = window.requestAnimFrame(callback);
                        return;
                    }
                }
                // 每幀執行導演類的 主循環 
                director.mainLoop();
                self._intervalId = window.requestAnimFrame(callback);
            }
        };
        // 間隔id,可通過該值來取消要執行的函數
        self._intervalId = window.requestAnimFrame(callback);
        // 是否暫停
        self._paused = false;
    },

可以看出,在cc.game._runMainLoop裏面,通過調用window.requestAnimFrame來實現循環執行callback。在callback裏面調用director.mainLoop(),來實現每一幀的更新。

下一講,我們將通過分析CCDirector.js這個類來了解整個遊戲渲染的流程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章