成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Cocos Creator 源碼解讀:引擎啟動(dòng)與主循環(huán)

開發(fā) 前端 游戲開發(fā)
本文會(huì)在宏觀上為大家解讀主循環(huán)與各個(gè)模塊之間的關(guān)系,對(duì)于各個(gè)模塊也會(huì)簡(jiǎn)單介紹,但不會(huì)深入到模塊的具體實(shí)現(xiàn)。

[[413098]]

本文轉(zhuǎn)載自微信公眾號(hào)「菜鳥小棧」,作者文弱書生陳皮皮 。轉(zhuǎn)載本文請(qǐng)聯(lián)系菜鳥小棧公眾號(hào)。

前言

本文基于 Cocos Creator 2.4.3 撰寫。

Ready

不知道你有沒(méi)有想過(guò),假如把游戲世界比作一輛汽車,那么這輛“汽車”是如何啟動(dòng),又是如何持續(xù)運(yùn)轉(zhuǎn)的呢?

如題,本文的內(nèi)容主要為 Cocos Creator 引擎的啟動(dòng)流程和主循環(huán)。

而在主循環(huán)的內(nèi)容中還會(huì)涉及到:組件的生命周期和計(jì)時(shí)器、緩動(dòng)系統(tǒng)、動(dòng)畫系統(tǒng)和物理系統(tǒng)等...

本文會(huì)在宏觀上為大家解讀主循環(huán)與各個(gè)模塊之間的關(guān)系,對(duì)于各個(gè)模塊也會(huì)簡(jiǎn)單介紹,但不會(huì)深入到模塊的具體實(shí)現(xiàn)。

畢竟如果要把每個(gè)模塊都“摸”一遍,那這篇文章怕是寫不完了。

Let's Go!

希望大家看完這篇文章之后能夠更加了解 Cocos Creator 引擎。

同時(shí)也希望本文可以起到「領(lǐng)進(jìn)門」的作用,大家一起加油呀~

另外《源碼解讀》系列(應(yīng)該)會(huì)持續(xù)更新,如果你想要皮皮來(lái)解讀解讀引擎的某個(gè)模塊,也歡迎留言告訴我,我...我考慮下哈哈哈~

正文

啟動(dòng)流程

index.html

對(duì)于 Web 平臺(tái)來(lái)說(shuō) index.html 文件就是程序的起點(diǎn)。

在默認(rèn)的 index.html 文件中,定義了游戲啟動(dòng)頁(yè)面的布局,加載了 main.js 文件,并且還有一段立即執(zhí)行的代碼。

這里截取 main.js 文件中一部分比較關(guān)鍵的代碼:

  1. // 加載引擎腳本 
  2. loadScript(debug ? 'cocos2d-js.js' : 'cocos2d-js-min.ec334.js'function () { 
  3.   // 是否開啟了物理系統(tǒng)? 
  4.   if (CC_PHYSICS_BUILTIN || CC_PHYSICS_CANNON) { 
  5.     // 加載物理系統(tǒng)腳本并啟動(dòng)引擎 
  6.     loadScript(debug ? 'physics.js' : 'physics-min.js', window.boot); 
  7.   } else { 
  8.     // 啟動(dòng)引擎 
  9.     window.boot(); 
  10.   } 
  11. }); 

上面這段代碼主要用于加載引擎腳本和物理系統(tǒng)腳本,腳本加載完成之后就會(huì)調(diào)用 main.js 中定義的 window.boot 函數(shù)。

原生平臺(tái)

對(duì)于原生平臺(tái),會(huì)在 {項(xiàng)目目錄}build\jsb-link\frameworks\runtime-src\Classes\AppDelegate.cpp 文件的 applicationDidFinishLaunching 函數(shù)中加載 main.js 文件。

——來(lái)自渡鴉大佬的補(bǔ)充

 代碼壓縮

腳本文件名中帶有 -min 字樣(如 index.min.js)一般代表著這個(gè)文件內(nèi)的代碼是被壓縮過(guò)的。

壓縮代碼可以節(jié)省代碼文件所占用的空間,加快文件加載速度,減少流量消耗,但同時(shí)也讓代碼失去了可閱讀性,不利于調(diào)試。

所以開啟調(diào)試模式后會(huì)直接使用未經(jīng)過(guò)壓縮的代碼文件,便于開發(fā)調(diào)試和定位錯(cuò)誤。

main.js

boot

對(duì)于不同平臺(tái) main.js 的內(nèi)容也有些許差異,這里我們忽略差異部分,只關(guān)注其中關(guān)鍵的共同行為。

關(guān)于 main.js 文件的內(nèi)容基本上就是定義了 window.boot 函數(shù)。

對(duì)于非 Web 平臺(tái),會(huì)在定義完之后直接就調(diào)用 window.boot 函數(shù),所以 main.js 就是他們的起點(diǎn)。

而 window.boot 函數(shù)內(nèi)部有以下關(guān)鍵行為:

  1. 定義 onStart 函數(shù):主要用于加載啟動(dòng)場(chǎng)景
  2. cc.assetManager.init(...):初始化 AssetManager
  3. cc.assetManager.loadScript(...):加載 src 目錄下的插件腳本
  4. cc.assetManager.loadBundle(...):加載項(xiàng)目中的 bundle
  5. cc.game.run(...):?jiǎn)?dòng)引擎

這部分的代碼就不貼了,小伙伴們可以看看自己的項(xiàng)目構(gòu)建后的 main.js 文件。

cc.game

cc.game 對(duì)象是 cc.Game 類的一個(gè)實(shí)例,cc.game 包含了游戲主體信息并負(fù)責(zé)驅(qū)動(dòng)游戲。

說(shuō)人話,cc.game 對(duì)象就是管理引擎生命周期的模塊,啟動(dòng)、暫停和重啟等操作都需要用到它。

[源碼] CCGame.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js

run

cc.game.run 函數(shù)內(nèi)指定了引擎配置和 onStart 回調(diào)并觸發(fā) cc.game.prepare() 函數(shù)。

源碼節(jié)選:

函數(shù):cc.game.run

  1. run: function (config, onStart) { 
  2.   // 指定引擎配置 
  3.   this._initConfig(config); 
  4.   this.onStart = onStart; 
  5.   this.prepare(game.onStart && game.onStart.bind(game)); 

[源碼] CCGame.js#L491: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js#L491

prepare

cc.game.prepare 函數(shù)內(nèi)主要在項(xiàng)目預(yù)覽時(shí)快速編譯項(xiàng)目代碼并調(diào)用 _prepareFinished 函數(shù)。

源碼節(jié)選:

函數(shù):cc.game.prepare

  1. prepare(cb) { 
  2.   // 已經(jīng)準(zhǔn)備過(guò)則跳過(guò) 
  3.   if (this._prepared) { 
  4.     if (cb) cb(); 
  5.     return
  6.   } 
  7.   // 加載預(yù)覽項(xiàng)目代碼 
  8.   this._loadPreviewScript(() => { 
  9.     this._prepareFinished(cb); 
  10.   }); 

[源碼] CCGame.js#L472: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js#L472

快速編譯

對(duì)于快速編譯的細(xì)節(jié),可以在項(xiàng)目預(yù)覽時(shí)打開瀏覽器的開發(fā)者工具,在 Sources 欄中搜索(Ctrl + P) __quick_compile_project__ 即可找到 __quick_compile_project__.js 文件。

_prepareFinished

cc.game._prepareFinished() 函數(shù)的作用主要為初始化引擎、設(shè)置幀率計(jì)時(shí)器和初始化內(nèi)建資源(effect 資源和 material 資源)。

當(dāng)內(nèi)建資源加載完成后就會(huì)調(diào)用 cc.game._runMainLoop() 啟動(dòng)引擎主循環(huán)。

源碼節(jié)選:

函數(shù):cc.game._prepareFinished

  1. _prepareFinished(cb) { 
  2.   // 初始化引擎 
  3.   this._initEngine(); 
  4.   // 設(shè)置幀率計(jì)時(shí)器 
  5.   this._setAnimFrame(); 
  6.   // 初始化內(nèi)建資源(加載內(nèi)置的 effect 和 material 資源) 
  7.   cc.assetManager.builtins.init(() => { 
  8.     // 打印引擎版本到控制臺(tái) 
  9.     console.log('Cocos Creator v' + cc.ENGINE_VERSION); 
  10.     this._prepared = true
  11.     // 啟動(dòng) mainLoop 
  12.     this._runMainLoop(); 
  13.     // 發(fā)射 ‘game_inited’ 事件(代表引擎已初始化完成) 
  14.     this.emit(this.EVENT_GAME_INITED); 
  15.     // 調(diào)用 main.js 中定義的 onStart 函數(shù) 
  16.     if (cb) cb(); 
  17.   }); 

[源碼] CCGame.js#L387: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js#L387

_setAnimFrame

對(duì)于 _prepareFinished 函數(shù)內(nèi)調(diào)用的 _setAnimFrame 函數(shù)這里必須提一下。

cc.game._setAnimFrame 函數(shù)內(nèi)部對(duì)不同的游戲幀率做了適配。

另外還對(duì) window.requestAnimationFrame 函數(shù)做了兼容性封裝,用于兼容不同的瀏覽器環(huán)境,具體的我們下面再說(shuō)。

這里就不貼 _setAnimFrame 函數(shù)的代碼了,有需要的小伙伴可自行查閱。

[源碼] CCGame.js#L564: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js#L564

_runMainLoop

cc.game._runMainLoop 函數(shù)的名字取得很簡(jiǎn)單直接,攤牌了它就是用來(lái)運(yùn)行 mainLoop 函數(shù)的。

源碼節(jié)選:

函數(shù):cc.game._runMainLoop

  1. _runMainLoop: function () { 
  2.   if (CC_EDITOR) return
  3.   if (!this._prepared) return
  4.   // 定義局部變量 
  5.   var self = this, callback, config = self.config, 
  6.     director = cc.director, 
  7.     skip = true, frameRate = config.frameRate; 
  8.   // 展示或隱藏性能統(tǒng)計(jì) 
  9.   debug.setDisplayStats(config.showFPS); 
  10.   // 設(shè)置幀回調(diào) 
  11.   callback = function (now) { 
  12.     if (!self._paused) { 
  13.       // 循環(huán)調(diào)用回調(diào) 
  14.       self._intervalId = window.requestAnimFrame(callback); 
  15.       if (!CC_JSB && !CC_RUNTIME && frameRate === 30) { 
  16.           if (skip = !skip) return
  17.       } 
  18.       // 調(diào)用 mainLoop 
  19.       director.mainLoop(now); 
  20.     } 
  21.   }; 
  22.   // 將在下一幀開始循環(huán)回調(diào) 
  23.   self._intervalId = window.requestAnimFrame(callback); 
  24.   self._paused = false

[源碼] CCGame.js#L612: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCGame.js#L612

通過(guò)以上代碼我們可以得知,_runMainLoop 函數(shù)主要通過(guò) window.requestAnimFrame 函數(shù)來(lái)實(shí)現(xiàn)循環(huán)調(diào)用 mainLoop 函數(shù)。

requestAnimFrame

window.requestAnimFrame 函數(shù)就是我們上面說(shuō)到的 _setAnimFrame 函數(shù)內(nèi)部對(duì)于 window.requestAnimationFrame 函數(shù)的兼容性封裝。

對(duì)前端不太熟悉的小伙伴可能會(huì)有疑問(wèn),window.requestAnimationFrame 又是啥,是用來(lái)干嘛的,又是如何運(yùn)行的?

requestAnimationFrame

簡(jiǎn)單來(lái)說(shuō),window.requestAnimationFrame 函數(shù)用于向?yàn)g覽器請(qǐng)求進(jìn)行一次重繪(repaint),并在重繪之前調(diào)用指定的回調(diào)函數(shù)。

window.requestAnimationFrame 函數(shù)接收一個(gè)回調(diào)作為參數(shù)并返回一個(gè)整數(shù)作為唯一標(biāo)識(shí),瀏覽器將會(huì)在下一個(gè)重繪之前執(zhí)行這個(gè)回調(diào);并且執(zhí)行回調(diào)時(shí)會(huì)傳入一個(gè)參數(shù),參數(shù)的值與 performance.now() 返回的值相等。

 Performance.now()

performance.now() 的返回值可以簡(jiǎn)單理解為瀏覽器窗口的運(yùn)行時(shí)長(zhǎng),即從打開窗口到當(dāng)前時(shí)刻的時(shí)間差。

[MDN] Performance.now(): https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now

回調(diào)函數(shù)的執(zhí)行次數(shù)通常與瀏覽器屏幕刷新次數(shù)相匹配,也就是說(shuō),對(duì)于刷新率為 60Hz 的顯示器,瀏覽器會(huì)在一秒內(nèi)執(zhí)行 60 次回調(diào)函數(shù)。

對(duì)于 window.requestAnimationFrame 函數(shù)的說(shuō)明到此為止,如果想要了解更多信息請(qǐng)自行檢索。

[MDN] window.requestAnimationFrame: https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestAnimationFrame

小結(jié)

 畫一張圖來(lái)對(duì)引擎的啟動(dòng)流程做一個(gè)小小的總結(jié)叭~

主循環(huán)

經(jīng)歷了一番波折后,終于來(lái)到了最期待的引擎主循環(huán)部分,話不多說(shuō),我們繼續(xù)!

cc.director

cc.director 對(duì)象是導(dǎo)演類 cc.Director 的實(shí)例,引擎通主要過(guò) cc.director 對(duì)象來(lái)管理游戲的邏輯流程。

[源碼] CCDirector.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCDirector.js

mainLoop

cc.director.mainLoop 函數(shù)可能是引擎中最關(guān)鍵的邏輯之一了,包含的內(nèi)容很多也很關(guān)鍵。

現(xiàn)在讓我們進(jìn)入 mainLoop 函數(shù)內(nèi)部來(lái)一探究竟吧!

源碼節(jié)選:

函數(shù):cc.Director.prototype.mainLoop

這里我選擇性剔除掉了函數(shù)中的一些代碼,還加了點(diǎn)注釋。

  1. mainLoop: function(now) { 
  2.   // 計(jì)算“全局”增量時(shí)間(DeltaTime) 
  3.   // 也就是距離上一次調(diào)用 mainLoop 的時(shí)間間隔 
  4.   this.calculateDeltaTime(now); 
  5.   // 游戲沒(méi)有暫停則進(jìn)行更新 
  6.   if (!this._paused) { 
  7.     // 發(fā)射 'director_before_update' 事件 
  8.     this.emit(cc.Director.EVENT_BEFORE_UPDATE); 
  9.     // 調(diào)用新增的組件(已啟用)的 start 函數(shù) 
  10.     this._compScheduler.startPhase(); 
  11.     // 調(diào)用所有組件(已啟用)的 update 函數(shù) 
  12.     this._compScheduler.updatePhase(this._deltaTime); 
  13.     // 更新調(diào)度器(cc.Scheduler) 
  14.     this._scheduler.update(this._deltaTime); 
  15.     // 調(diào)用所有組件(已啟用)的 lateUpdate 函數(shù) 
  16.     this._compScheduler.lateUpdatePhase(this._deltaTime); 
  17.     // 發(fā)射 'director_after_update' 事件 
  18.     this.emit(cc.Director.EVENT_AFTER_UPDATE); 
  19.     // 銷毀最近被移除的實(shí)體(節(jié)點(diǎn)) 
  20.     Obj._deferredDestroy(); 
  21.   } 
  22.   // 發(fā)射 'director_before_draw' 事件 
  23.   this.emit(cc.Director.EVENT_BEFORE_DRAW); 
  24.   // 渲染游戲場(chǎng)景 
  25.   renderer.render(this._scene, this._deltaTime); 
  26.   // 發(fā)射 'director_after_draw' 事件 
  27.   this.emit(cc.Director.EVENT_AFTER_DRAW); 
  28.   // 更新事件管理器的事件監(jiān)聽(cc.eventManager 已被廢棄) 
  29.   eventManager.frameUpdateListeners(); 
  30.   // 累加游戲運(yùn)行的總幀數(shù) 
  31.   this._totalFrames++; 

[源碼] CCDirector.js#L843: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCDirector.js#L843

接下來(lái)我們來(lái)對(duì)主循環(huán)中的關(guān)鍵點(diǎn)一一進(jìn)行分解。

ComponentScheduler

cc.director 對(duì)象中的 _compScheduler屬性 是 ComponentScheduler 類的實(shí)例。

大多數(shù)小伙伴可能對(duì)于 ComponentScheduler 這個(gè)類沒(méi)有什么印象,我來(lái)簡(jiǎn)單解釋一下。

將 ComponentScheduler 的名字直譯過(guò)來(lái)就是“組件調(diào)度器”,從名字上就可以看出,這個(gè)類是用來(lái)調(diào)度組件的。

說(shuō)人話,ComponentScheduler 類是用來(lái)集中調(diào)度(管理)游戲場(chǎng)景中所有組件(cc.Component)的生命周期的。

文字不夠直觀,看完下面這張圖大概就懂了:

[源碼] component-scheduler.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/component-scheduler.js

startPhase

 mainLoop 函數(shù)代碼片段:

  1. // 調(diào)用上一幀新增(且已啟用)的組件的 start 函數(shù) 
  2. this._compScheduler.startPhase(); 

組件的 start 回調(diào)函數(shù)會(huì)在組件第一次激活前,也就是第一次執(zhí)行 update 之前觸發(fā)。

在組件的一生中 start 回調(diào)只會(huì)被觸發(fā)一次。

而 start 則會(huì)等到下一次主循環(huán) mainLoop() 時(shí)才觸發(fā)。

 知識(shí)補(bǔ)充

生命周期中的 onLoad 和 onEnable 是由 NodeActivator 類的來(lái)管理的:

  • onLoad 在節(jié)點(diǎn)首次激活時(shí)觸發(fā)
  • onEnable 在組件每次被啟用時(shí)都會(huì)觸發(fā)

NodeActivator

NodeActivator 類主要用于激活和反激活節(jié)點(diǎn)以及節(jié)點(diǎn)身上的組件。

cc.director 對(duì)象中就擁有一個(gè)實(shí)例 _nodeActivator。如激活節(jié)點(diǎn)時(shí)會(huì)調(diào)用 cc.director._nodeActivator.activateNode(this, value);。

[源碼] node-activator.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/node-activator.js

updatePhase

mainLoop 函數(shù)代碼片段:

  1. // 調(diào)用所有(已啟用)組件的 update 函數(shù) 
  2. this._compScheduler.updatePhase(deltaTime); 

組件的 update 回調(diào)每一幀都會(huì)被觸發(fā)一次。

lateUpdatePhase

 mainLoop 函數(shù)代碼片段:

  1. // 調(diào)用所有組件(已啟用)的 lateUpdate 函數(shù) 
  2. this._compScheduler.lateUpdatePhase(deltaTime); 

組件的 lateUpdate 回調(diào)會(huì)在「組件 update 回調(diào)執(zhí)行后、調(diào)度器(cc.Scheduler)更新后」被觸發(fā)。

調(diào)度器(cc.Scheduler)的更新內(nèi)容包括緩動(dòng)、動(dòng)畫和物理等,這一點(diǎn)下面會(huì)展開。

ParticleSystem

BTW,粒子系統(tǒng)組件(cc.ParticleSystem)就是在 lateUpdate 回調(diào)函數(shù)中進(jìn)行更新的。

[源碼] CCParticleSystem.js#L923: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/particle/CCParticleSystem.js#L923

一個(gè)建議

請(qǐng)謹(jǐn)慎使用 update 和 lateUpdate 回調(diào),因?yàn)樗鼈兠恳粠紩?huì)被觸發(fā),如果 update 或 lateUpdate 內(nèi)的邏輯過(guò)多,就會(huì)使得每一幀的執(zhí)行時(shí)間(即幀時(shí)間 Frame time)都變長(zhǎng),導(dǎo)致游戲運(yùn)行幀數(shù)降低或出現(xiàn)不穩(wěn)定的情況。

注意:這個(gè)建議不是不讓你用,該用還得用,只是不要濫用,不要啥玩意都往里邊塞~

Scheduler

cc.director 對(duì)象的 _scheduler 屬性是 cc.Scheduler 類的一個(gè)實(shí)例。

cc.Scheduler 是負(fù)責(zé)觸發(fā)回調(diào)函數(shù)的類。

[源碼] Scheduler.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/Scheduler.js

 mainLoop 函數(shù)代碼片段:

你絕對(duì)猜不到下面這一行看起來(lái)如此平平無(wú)奇的代碼執(zhí)行之后會(huì)發(fā)生什么。

  1. // 更新調(diào)度器(cc.Scheduler 類實(shí)例) 
  2. this._scheduler.update(this._deltaTime); 

cc.director.mainLoop 函數(shù)中使用調(diào)度器 _scheduler 的 update 函數(shù)來(lái)分發(fā) update,在調(diào)度器內(nèi)部會(huì)根據(jù)優(yōu)先級(jí)先后觸發(fā)各個(gè)系統(tǒng)模塊和組件計(jì)時(shí)器的更新。

系統(tǒng)模塊

調(diào)度器的更新會(huì)先觸發(fā)以下系統(tǒng)模塊的更新:

  • ActionManager
  • AnimationManager
  • CollisionManager
  • PhysicsManager
  • Physics3DManager
  • InputManager

以上這些模塊都以 cc.director._scheduler.scheduleUpdate() 的方式注冊(cè)到調(diào)度器上,因?yàn)檫@些模塊每一幀都需要進(jìn)行更新。

除了 InputManager 以外的模塊的優(yōu)先級(jí)都為 cc.Scheduler.PRIORITY_SYSTEM,也就是「系統(tǒng)優(yōu)先級(jí)」,會(huì)優(yōu)先被觸發(fā)。

ActionManager

ActionManager 即動(dòng)作管理器,用于管理游戲中的所有動(dòng)作,也就是緩動(dòng)系統(tǒng) Action 和 Tween(其實(shí)它們本質(zhì)上是同一種東西)。

[源碼] CCActionManager.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/actions/CCActionManager.js

AnimationManager

AnimationManager 即動(dòng)畫管理器,用于管理游戲中的所有動(dòng)畫,驅(qū)動(dòng)節(jié)點(diǎn)上的 Animation 組件播放動(dòng)畫。

[源碼] animation-manager.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/animation/animation-manager.js

CollisionManager

CollisionManager 即碰撞組件管理器,用于處理節(jié)點(diǎn)之間的碰撞組件是否產(chǎn)生了碰撞,并調(diào)用相應(yīng)回調(diào)函數(shù)。

[源碼] CCCollisionManager.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/collider/CCCollisionManager.js

PhysicsManager

PhysicsManager 即物理系統(tǒng)管理器,內(nèi)部以 Box2D 作為 2D 物理引擎,加以封裝并開放部分常用的接口。同時(shí) PhysicsManager 還負(fù)責(zé)管理碰撞信息的分發(fā)。

[源碼] CCPhysicsManager.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/physics/CCPhysicsManager.js

Physics3DManager

Physics3DManager 即3D 物理系統(tǒng)管理器,Cocos Creator 中的 3D 物理引擎有 Cannon.js 和 Builtin 可選,Physics3DManager 給它們封裝了統(tǒng)一的常用接口。

[源碼] physics-manager.ts: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/3d/physics/framework/physics-manager.ts

InputManager

InputManager 即輸入事件管理器,用于管理所有輸入事件。開發(fā)者主動(dòng)啟用加速度計(jì)(Accelerometer)之后,引擎會(huì)定時(shí)通過(guò) InputManager 發(fā)送 cc.SystemEvent.EventType.DEVICEMOTION 事件(默認(rèn)間隔為 0.2 秒)。

[源碼] CCInputManager.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d\core\platform\CCInputManager.js

組件計(jì)時(shí)器

相信大多數(shù)小伙伴都使用過(guò)組件的 schedule 和 scheduleOnce 函數(shù),主要用來(lái)延遲或重復(fù)執(zhí)行指定的函數(shù)。

實(shí)際上,cc.Component 的 schedule 函數(shù)依賴的也是 cc.Scheduler 類,具體使用的也是 cc.director 對(duì)象中的 _scheduler 實(shí)例。

組件的 schedule 函數(shù)在 cc.director._scheduler.schedule 函數(shù)之外加了一層封裝,「以組件自身作為 target,這樣一來(lái)組件內(nèi)的定時(shí)任務(wù)就與組件生命周期綁定,當(dāng)組件被銷毀時(shí)定時(shí)任務(wù)也會(huì)被移除。」

而 scheduleOnce 函數(shù)則是在組件的 schedule 接口之外又加了一層簡(jiǎn)單的封裝,寫死只會(huì)在指定時(shí)間后執(zhí)行一次。

[源碼] CCComponent.js#L555: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/components/CCComponent.js#L555

[文檔] 使用計(jì)時(shí)器: http://docs.cocos.com/creator/manual/zh/scripting/scheduler.html

setTimeout & setInterval

另外我還注意到,有不少小伙伴還不是很清楚組件的計(jì)時(shí)器和 setTimeout、setInterval 之間的區(qū)別和用法,那就趁這個(gè)機(jī)會(huì)簡(jiǎn)單講一下吧~

首先,setTimeout 和 setInterval 函數(shù)都是由瀏覽器或 Node.js 這類 runtime 所提供的接口。

setTimeout 函數(shù)用于設(shè)置一個(gè)定時(shí)器,該定時(shí)器在定時(shí)器到期后執(zhí)行一個(gè)函數(shù)或指定的一段代碼。

setInterval 函數(shù)用于重復(fù)調(diào)用一個(gè)函數(shù)或執(zhí)行一個(gè)代碼段,在每次調(diào)用之間具有固定的時(shí)間延遲。

知識(shí)補(bǔ)充

在瀏覽器中 setTimeout 和 setInterval 函數(shù)的最小延時(shí)(間隔)是 4ms。

如果是未激活(處于后臺(tái))的標(biāo)簽頁(yè)(tab),最小延時(shí)(間隔)則加長(zhǎng)到 1000ms。

舉個(gè)栗子

假如我在當(dāng)前標(biāo)簽頁(yè)設(shè)置了一個(gè)每 500ms 輸出一個(gè) log 的定時(shí)器,當(dāng)我切換到別的標(biāo)簽頁(yè)之后,那么這個(gè)定時(shí)器就會(huì)變成每 1000ms 才輸出一個(gè) log。

像這樣(可以自己跑跑看):

  1. setInterval(() => { 
  2.   console.log(Date.now()); 
  3. }, 500); 
  4. // 模擬輸出 
  5. // 標(biāo)簽頁(yè)在前臺(tái) 
  6. // 1604373521000 
  7. // 1604373521500 
  8. // 1604373522000 
  9. // 切換到別的標(biāo)簽頁(yè)后 
  10. // 1604373523000 
  11. // 1604373524000 
  12. // 1604373525000 

區(qū)別 & 用法

組件的計(jì)時(shí)器依賴于引擎的 mainLoop() 和組件自身,如果引擎被暫停,那么組件的計(jì)時(shí)器也會(huì)被暫停,如果組件或組件所在的節(jié)點(diǎn)被銷毀了,那么計(jì)時(shí)器也會(huì)失效。

setTimeout() 和 setInterval() 都依賴于當(dāng)前所處的 window 對(duì)象,也就是說(shuō)只要當(dāng)前瀏覽器標(biāo)簽頁(yè)不關(guān)閉,setTimeout() 和 setInterval() 都還是會(huì)執(zhí)行的。

當(dāng)你需要在組件內(nèi)部定時(shí)或重復(fù)執(zhí)行某一函數(shù)或操作某個(gè)節(jié)點(diǎn),那么可以使用組件的計(jì)時(shí)器。

讓我們想象一個(gè)場(chǎng)景:

在當(dāng)前場(chǎng)景中的某個(gè)腳本內(nèi)使用 setInterval() 來(lái)重復(fù)移動(dòng)場(chǎng)景中的某個(gè)節(jié)點(diǎn),當(dāng)我們切換場(chǎng)景后會(huì)發(fā)生什么?

當(dāng)定時(shí)器再次調(diào)用回調(diào)嘗試移動(dòng)節(jié)點(diǎn)的時(shí)候,會(huì)無(wú)法找到目標(biāo)節(jié)點(diǎn)而報(bào)錯(cuò),因?yàn)楣?jié)點(diǎn)已經(jīng)跟著之前的場(chǎng)景一起被銷毀了,而定時(shí)器還在繼續(xù)執(zhí)行。

這種情況下使用組件的計(jì)時(shí)器就不會(huì)有這種問(wèn)題,因?yàn)橛?jì)時(shí)器會(huì)隨著組件的銷毀而被清除。

而當(dāng)我們需要執(zhí)行一些與游戲場(chǎng)景沒(méi)有關(guān)聯(lián)的事情的時(shí)候,就可以考慮使用 setTimeout() 或 setInterval()。

當(dāng)然能用組件計(jì)時(shí)器的話最好還是用組件計(jì)時(shí)器啦~

小結(jié)

 同樣也畫一張圖來(lái)小小總結(jié)一下 Scheduler。

總結(jié)

關(guān)于引擎的啟動(dòng)流程和主循環(huán)就解讀到這里啦。

如果有遺漏或錯(cuò)誤的地方,也歡迎大家提出來(lái),畢竟熬夜寫文章精神恍惚漏了也是情有可原的對(duì)吧哈哈哈~

最后的最后,再畫一張圖來(lái)做一個(gè)最后的總結(jié)~

逐漸愛上畫圖~

 

責(zé)任編輯:武曉燕 來(lái)源: 菜鳥小棧
相關(guān)推薦

2022-10-19 13:43:42

CocosOpenHarmon3D游戲引擎

2014-11-14 14:42:09

IntelCocos引擎

2023-06-08 08:16:33

TickerPixiJS

2023-03-13 15:03:05

鴻蒙ArkUI

2017-08-16 14:05:59

Cocos Creat

2015-04-23 17:06:33

Cocos開發(fā)者

2021-01-22 07:43:35

Filecoin循環(huán)供應(yīng)

2014-08-28 10:20:03

游戲設(shè)計(jì)

2015-07-06 17:12:31

游戲開發(fā)引擎cocos游戲引擎

2015-07-06 17:36:17

Cocos游戲開發(fā)引擎

2023-12-14 13:28:00

Spring流程Web

2015-06-15 10:32:44

Java核心源碼解讀

2024-10-28 08:15:32

2016-08-29 19:12:52

JavascriptBackbone前端

2010-01-27 10:37:17

Android圖片瀏覽

2015-07-08 16:38:10

Cocos游戲引擎

2021-05-06 07:58:57

Spring BeanIOCAOP

2010-01-26 13:55:57

Android分享功能

2024-09-06 09:37:45

WebApp類加載器Web 應(yīng)用

2010-01-28 15:54:19

Android單元測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日本一区二区视频 | 999久久久久久久久 国产欧美在线观看 | 欧美精品一区二区三区一线天视频 | 日韩电影a | 久久激情av | 高清视频一区二区三区 | 日韩视频一区二区三区 | 视频一区二区在线观看 | 91av久久久| 91精品久久久久久久久久小网站 | 国产福利视频导航 | 国产精品免费一区二区 | 91久久综合亚洲鲁鲁五月天 | 一区二区三区中文字幕 | 国产精品久久久久久久久久东京 | 国产成人亚洲精品 | 亚洲欧美在线观看 | 国产在线中文字幕 | 欧美在线a| 国产精品一区二区不卡 | www.日本精品 | 日韩精品在线一区 | 久草久草久草 | 国产免费观看一级国产 | 三级黄片毛片 | 91国内精精品久久久久久婷婷 | 成人国产精品视频 | 四虎成人免费电影 | 激情毛片 | 国产一区二区三区日韩 | 9色视频在线 | 日韩精品无码一区二区三区 | 久草视频网站 | 黄片毛片免费观看 | 日韩视频在线一区二区 | 91精品久久久久久久久 | 精品永久| 日韩三片 | 亚洲色图第一页 | 日韩在线观看网站 | 国产专区视频 |