In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-22 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article focuses on "Cocos Creator source code interpretation of what is the engine start and the main loop", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Next let the editor to take you to learn "Cocos Creator source code interpretation of what is the engine start and the main loop" it!
Start the process index.html
For Web platform index.html files are the absolute starting point.
In the default index.html file, the layout of the game startup page is defined, and there is a piece of code that executes immediately.
Here is to intercept some of the more critical code in the file:
/ / load engine script
LoadScript (debug? 'cocos2d-js.js': 'cocos2d-js-min.ec334.js', function () {
/ / is the physical system turned on?
If (CC_PHYSICS_BUILTIN | | CC_PHYSICS_CANNON) {
/ / load the physical system script and start the engine
LoadScript (debug? 'physics.js':' physics-min.js', window.boot)
} else {
/ / start the engine
Window.boot ()
}
});
The above code is mainly used to load engine scripts and physical system scripts, and after the script is loaded, the window.boot () function defined in main.js is called.
Code compression
The script file name with the word-min generally means that the code in the file is compressed.
Compressing the code can save the space occupied by the code file, speed up the file loading speed, and reduce the traffic consumption, but at the same time, it also makes the code lose readability, which is not conducive to debugging.
Therefore, when debug mode is turned on, uncompressed code files will be used directly to facilitate development, debugging and error location.
Main.jswindow.boot ()
There are also some differences in the content of main.js for different platforms. Here we ignore the differences and focus only on the key common behaviors.
The content of the main.js file basically defines the window.boot () function.
For non-Web platforms, the window.boot () function is called directly after the definition, so main.js is their starting point.
The window.boot () function has the following key behavior:
Define onStart callback function: mainly used to load startup scenario cc.assetManager.init (...): initialize AssetManagercc.assetManager.loadScript (...): load plug-in script cc.assetManager.loadBundle (...) in the src directory: load bundlecc.game.run (...) in the project: start the engine
This part of the code will not be posted, friends can take a look at their own project built after the main.js file.
Cc.game
The cc.game object is an instance of the cc.Game class. Cc.game contains the game body information and is responsible for driving the game.
In human terms, the cc.game object is the module that manages the engine life cycle, and is needed for startup, pause, and restart operations.
Run ()
The engine configuration and onStart callback are specified in the cc.game.run () function and the cc.game.prepare () function is triggered.
Run: function (config, onStart) {
/ / specify engine configuration
This._initConfig (config)
This.onStart = onStart
This.prepare (game.onStart & & game.onStart.bind (game))
} prepare ()
Within the cc.game.prepare () function, the project code is compiled quickly and the _ prepareFinished () function is called during the project preview.
Prepare (cb) {
/ / if you have already prepared, skip
If (this._prepared) {
If (cb) cb ()
Return
}
/ / load preview project code
This._loadPreviewScript () = > {
This._prepareFinished (cb)
});
}
For quick compilation details, you can open the browser's developer tool during the project preview and search the Sources bar for (Ctrl + P) _ quick_compile_project__ to find the _ _ quick_compile_project__.js file.
_ prepareFinished ()
The cc.game._prepareFinished () function is mainly used to initialize the engine, set the frame rate timer, and initialize built-in resources (effect resources and material resources).
When the built-in resource is loaded, cc.game._runMainLoop () is called to start the engine main loop.
_ prepareFinished (cb) {
/ / initialize the engine
This._initEngine ()
/ / set the frame rate timer
This._setAnimFrame ()
/ / initialize built-in resources (load built-in effect and material resources)
Cc.assetManager.builtins.init () = > {
/ / print engine version to the console
Console.log ('Cocos Creator v' + cc.ENGINE_VERSION)
This._prepared = true
/ / start mainLoop
This._runMainLoop ()
/ / launch the 'game_inited' event (that is, the engine has been initialized)
This.emit (this.EVENT_GAME_INITED)
/ / call the onStart function defined in main.js
If (cb) cb ()
});
}
_ setAnimFrame ()
Cc.game._setAnimFrame () adapts to different game frame rates internally.
In addition, the window.requestAnimationFrame () interface is encapsulated for compatibility with different browser environments, which we'll talk about below.
The code of _ setAnimFrame () will not be posted here, and the friends who need it can check it on their own.
_ runMainLoop ()
The name of the function cc.game._runMainLoop () is simple and straightforward, and it has been showdown that it is used to run the mainLoop () function.
Let's take a look at the code:
_ runMainLoop: function () {
If (CC_EDITOR) return
If (! this._prepared) return
/ / define local variables
Var self = this, callback, config = self.config
Director = cc.director
Skip = true, frameRate = config.frameRate
/ / Show or hide performance statistics
Debug.setDisplayStats (config.showFPS)
/ / set frame callback
Callback = function (now) {
If (! self._paused) {
/ / Loop call callback
Self._intervalId = window.requestAnimFrame (callback)
If (! CC_JSB & &! CC_RUNTIME & & frameRate = 30) {
If (skip =! skip) return
}
/ / call mainLoop
Director.mainLoop (now)
}
}
/ / Loop callback will be started in the next frame
Self._intervalId = window.requestAnimFrame (callback)
Self._paused = false
}
From the above code, we can see that _ runMainLoop () mainly uses the window.requestAnimFrame () interface to call the mainLoop () function in a loop.
Window.requestAnimFrame ()
Window.requestAnimFrame () is the compatibility encapsulation of window.requestAnimationFrame () within _ setAnimFrame () that we mentioned above.
People who are not familiar with the front end may wonder, what is window.requestAnimationFrame (), what is it used for, and how does it work?
Window.requestAnimationFrame ()
To put it simply, window.requestAnimationFrame () is used to request a repaint from the browser and to call the specified callback function before redrawing.
Window.requestAnimationFrame () takes a callback as a parameter and returns an integer as a unique identity, which the browser will execute before the next redraw; and when the callback is performed, a parameter will be passed in with a value equal to the value returned by performance.now ().
The return value of performance.now () can be simply understood as the running time of the browser window, that is, the time difference between the opening of the window and the current time.
MDN documents: https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now
The number of times the callback function is executed usually matches the number of screen refreshes in the browser, that is, for a display with a refresh rate of 60Hz, the browser executes the callback function 60 times in a second.
So much for the description of window.requestAnimationFrame (). If you want to know more, please search it yourself.
Summary
Draw a picture to make a small summary of the engine startup process.
Main cycle
After a lot of twists and turns, finally came to the most anticipated part of the main cycle of the engine, without saying much, let's go on!
Cc.director
The cc.director object is an instance of the director class cc.Director. Engine pass mainly manages the logical flow of the game through the cc.director object.
CCDirector.js: https://github.com/cocos-creator/engine/blob/2.4.3/cocos2d/core/CCDirector.js
MainLoop ()
The cc.director.mainLoop () function is probably one of the most critical logic in the engine, and it contains a lot of content that is also critical.
Now let's go inside the mainLoop () function to find out.
Here I selectively removed some of the code from the function and made some comments:
MainLoop: function (now) {
/ / calculate the "global" incremental time (DeltaTime)
/ / that is, the time interval since the last call to mainLoop
This.calculateDeltaTime (now)
/ / update if the game is not paused
If (! this._paused) {
/ / launch the 'director_before_update' event
This.emit (cc.Director.EVENT_BEFORE_UPDATE)
/ / call the start function of the new component (enabled)
This._compScheduler.startPhase ()
/ / call the update functions of all components (enabled)
This._compScheduler.updatePhase (this._deltaTime)
/ / Update the scheduler (cc.Scheduler)
This._scheduler.update (this._deltaTime)
/ / call the lateUpdate functions of all components (enabled)
This._compScheduler.lateUpdatePhase (this._deltaTime)
/ / launch the 'director_after_update' event
This.emit (cc.Director.EVENT_AFTER_UPDATE)
/ / destroy recently removed entities (nodes)
Obj._deferredDestroy ()
}
/ / launch the 'director_before_draw' event
This.emit (cc.Director.EVENT_BEFORE_DRAW)
/ / render the game scene
Renderer.render (this._scene, this._deltaTime)
/ / launch the 'director_after_draw' event
This.emit (cc.Director.EVENT_AFTER_DRAW)
/ / Update event Manager event snooping (cc.eventManager has been deprecated)
EventManager.frameUpdateListeners ()
/ / accumulate the total number of frames the game is running
This._totalFrames++
}
Next let's decompose the key points in the main cycle one by one.
ComponentScheduler
The _ compScheduler property in the cc.director object is an instance of the ComponentScheduler class.
Most of my friends probably have no impression of the class ComponentScheduler, so let me explain it briefly.
The literal translation of the name of ComponentScheduler is "component Scheduler". As you can see from the name, this class is used to schedule components.
In human terms, the ComponentScheduler class is used to centrally schedule (manage) the life cycle of all components (cc.Component) in a game scenario.
The text is not intuitive enough. After reading the following picture, you will probably understand:
StartPhase// calls the start function of the new component (enabled)
This._compScheduler.startPhase ()
The component's start callback function is triggered before the component is first activated, that is, before the update is executed for the first time.
Start callbacks are triggered only once in the lifetime of a component, as are onLoad and onEnable.
Except that onLoad and onEnable are managed by an instance of the NodeActivator class:
OnLoad triggers when the node is activated. OnEnable triggers when the component is enabled.
Start, on the other hand, is not triggered until the next main loop mainLoop ().
NodeActivator
The NodeActivator class is mainly used to enable and disable nodes and components on their bodies.
There is an instance _ nodeActivator in the cc.director object, which is used to enable and disable all nodes in the game.
Like this: cc.director._nodeActivator.activateNode (this, value)
UpdatePhase// calls update functions for all components (enabled)
This._compScheduler.updatePhase (deltaTime)
The component's update function is triggered once at every frame.
LateUpdatePhase// calls lateUpdate functions for all components (enabled)
This._compScheduler.lateUpdatePhase (deltaTime)
The lateUpdate function of the component is triggered after the update and scheduler cc.Scheduler are updated. Updates to the scheduler include ease, animation, and physics, which will be expanded below.
ParticleSystem
BTW, the particle system component (cc.ParticleSystem) is updated in the lateUpdate callback function.
Tips
Use update and lateUpdate callbacks with caution, as they are triggered every frame, and if there is too much logic in the update or lateUpdate, it will make the execution time of each frame (that is, the frame time Frame time) longer, resulting in a decrease in the number of frames running the game or instability.
Note that it's not forbidden to use it, you have to use it when you need it, but don't abuse it and don't race everything into it.
Scheduler
The _ scheduler property of the cc.director object is an instance of the cc.Scheduler class.
Cc.Scheduler is the class responsible for triggering the callback function.
You'll never guess what happens after the execution of a line that looks so mediocre.
/ / Update the scheduler (cc.Scheduler class instance)
This._scheduler.update (this._deltaTime)
The _ scheduler.update () function is used in cc.director.mainLoop () to distribute the update, and updates of each system module and component timer are triggered within the cc.director._scheduler according to priority.
System module
The update of the scheduler first triggers the update of the following system modules:
ActionManagerAnimationManagerCollisionManagerPhysicsManagerPhysics3DManagerInputManager
All of these modules are registered with the scheduler as cc.director._scheduler.scheduleUpdate () because they need to be updated at every frame.
The priority of all modules except InputManager is cc.Scheduler.PRIORITY_SYSTEM, that is, the system priority, which will be triggered first.
ActionManager
ActionManager, the Action Manager, is used to manage all the actions in the game, that is, the ease systems Action and Tween (essentially the same thing).
AnimationManager
AnimationManager, the Animation Manager, manages all the animations in the game and drives the Animation components on the nodes to play the animations.
CollisionManager
CollisionManager is the collision component manager, which is used to deal with whether the collision components between nodes have collided, and call the corresponding callback function.
PhysicsManager
PhysicsManager is the physical system manager, which uses Box2D as the 2D physics engine to encapsulate and open some commonly used interfaces. At the same time, PhysicsManager is responsible for managing the distribution of collision information.
Physics3DManager
Physics3DManager is the 3D physical system manager. The 3D physics engine in Cocos Creator has Cannon.js and Builtin options, and Physics3DManager encapsulates a unified common interface for them.
InputManager
InputManager, the input event manager, is used to manage all input events. After the developer actively enables the accelerometer (Accelerometer), the engine periodically sends cc.SystemEvent.EventType.DEVICEMOTION events over the InputManager (the default interval is 0.2s).
Component timer
It is believed that most partners have used the schedule () and scheduleOnce () interfaces of components, which are mainly used to execute functions repeatedly or regularly.
In fact, the schedule () interface of cc.Component also relies on the cc.Scheduler class, using the _ scheduler instance in the cc.director object.
The schedule () interface of the component adds a layer of encapsulation to the cc.director._scheduler.schedule () interface, using the component itself as a target, so that the timing task within the component is bound to the component life cycle, and the timing task is removed when the component is destroyed.
The scheduleOnce () interface adds another layer of encapsulation to the schedule () interface of the component, which is only executed once after a specified time.
SetTimeout & setInterval
Both setTimeout () and setInterval () are interfaces provided by browsers or runtime such as Node.js.
The setTimeout () interface is used to set a timer that executes a function or a specified piece of code after the timer expires. The setInterval () interface is used to repeatedly call a function or execute a code snippet with a fixed time delay between each call.
Add a little bit of knowledge:
The minimum latency (interval) for setTimeout () and setInterval () in the browser is 4ms.
If it is an inactive (background) tab (tab), the minimum delay (interval) is lengthened to 1000ms.
Take a chestnut.
If I set a timer on the current tab that outputs one log per 500ms, when I switch to another tab, the timer will output only one log per 1000ms.
Like this, if you are interested, you can try it yourself:
SetInterval () = > {
Console.log (new Date () .getTime ())
}, 500)
/ / Analog output
/ / the tab is at the front desk.
/ / 1604373521000
/ / 1604373521500
/ / 1604373522000
/ / after switching to another tab
/ / 1604373523000
/ / 1604373524000
/ / 1604373525000 distinction & usage
The timer of the component depends on the mainLoop () of the engine and the component itself. If the engine is paused, the timer of the component will also be paused, and if the component or the node on which the component resides is destroyed, the timer will fail.
Both setTimeout () and setInterval () depend on the window object in which they are currently located, which means that both setTimeout () and setInterval () will execute as long as the current browser tab is not closed.
When you need to perform a function or manipulate a node regularly or repeatedly within a component, you can use the component's timer.
Let's imagine a scenario:
Using setInterval () to repeatedly move a node in the scene within a script in the current scene, what happens when we switch the scene?
When the timer calls the callback again to try to move the node, the target node cannot be found and an error is reported, because the node has been destroyed along with the previous scene, and the timer continues to execute.
In this case, the timer that uses the component will not have this problem, because the timer will be cleared as the component is destroyed.
When we need to do something that has nothing to do with the game scenario, we can consider using setTimeout () or setInterval ().
Of course, if you can use a component timer, you'd better use a component timer.
Summary
Still draw a picture to sum up the Scheduler.
At this point, I believe that everyone on the "Cocos Creator source code interpretation of what is the engine start and the main loop" have a deeper understanding, might as well to the actual operation of it! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.