从官方对creator引擎的产品定位中我们不难得知,cocos Creator是基于组件化脚本化开发,更具体点是基于js的脚本化,组件化开发

我们在组件脚本开发的时候首先注意的必定就是其生命周期了,目前creator提供给我们的生命周期回调函数主要有onLoad,start,update,lateUpdate,onDestroy,onEnable,
onDisable,我
们可以简单描述一下这些回调触发的时机

onLoad回调函数会在节点首次激活时触发,在任何start函数调用前执行

start回调函数会在组件第一次激活前,也就是第一次执行 update 之前触发

update在组件进行更新时执行, 每一帧渲染前更新物体的行为

lateUpdate在所有组件的 update 都执行完之后

onDestroy当组件或者所在节点调用了 destroy()

onEnable当组件的 enabled 属性从 false 变为 true 时,或者所在节点的 active 属性从 false 变为 true 时

onDisable当组件的 enabled 属性从 true 变为 false 时,或者所在节点的 active 属性从 true 变为 false 时

需要注意的是我们的初始化通常在start函数而不再onload函数中的原因:onload是场景加载完成执行,start是当前组件开始运行时执行。假设每个组件的初始化都在onload完成,当一个节点的初始化依赖于另一个节点的属性时,就有可能出现异常,因为有可能另一个节点还没有执行onload。而start是所有组件的onload都执行完了才会执行,这时无论获取哪个节点的属性都不会有问题,因为那个节点已经初始化完成了。所以节点的UI初始化最好放在start中。
知道了这些,我们在做开发的时候就会有了一个大概的流程概念,在合适的时机处理自己想要的操作,晓得这些回调函数是在什么时候触发的了,天生丽质的宝宝们都会追根到底,那为啥你说他那个时候触发他就那个时候触发啊,ok,接下来,我们就详细的解析一

从cocos官方文档中我们可得知 Cocos Creator 的引擎部分包括 JavaScript、Cocos2d-x-lite 和 adapter 三个部分,引擎代码大致分为js和原生的c++ 两种类型,分别在引擎安装目录resources/engine 和 resources/cocos2d-x下。

咱们就从web平台来分析吧,主要看的就是engine\cocos2d 目录下的源码。

我们常说打出来的空包就要1-2兆,其实一部分原因就是需要把这些模块依赖给打包进去…em,有点跑题了

creator对应打出来的web包,对应的cocos2d-js-min.js文件所有模块的源码。整个文件的执行周期,main.js是creator引擎的入口,他会在cocos2d-js-min.js加载完之后开始运行游戏
如果简化main.js 的内容大概是这样的

//main.js
window.boot =function() {//loading页面相关function setLoadingDisplay (){...};//主要是对Web和native游戏场景尺寸或者朝向的处理以及加载scene相关var onStart = function(){//以及调用上方的setLoadingDisplay 函数设置loading相关};//当前的游戏配置var option = function(){...};//s获取_CCSettings变量进行处理cc.AssetLibrary.init({...});//cc.game包含游戏主体信息并负责驱动游戏的游戏对象,传入配置参数//运行游戏,并且指定引擎配置和 onStart 的回调cc.game.run(option, onStart);
}
//调用
window.boot();

这里我们可以看到,如果简化来看,boot中就是声明和设置一些配置信息或者一些出来,以传参的形式传到run函数中
在run方法中,会根据配置进行引擎的准备工作,简单流程如下

//game
var game = {//运行游戏,并且指定引擎配置和 onStart 的回调。run(config, onStart){// 注册配置数据      this._initConfig(config);this.onStart = onStart;// 开始准备      this.prepare(game.onStart && game.onStart.bind(game));},//准备引擎prepare(cb){//如果已准备则执行回调返回if (this._prepared){          if (cb) cb();       return;    }let jsList = this.config.jsList;if (jsList && jsList.length > 0){var self = this;  // 加载准备脚本之后调用         cc.loader.load(jsList, function (err) {                if (err) throw new Error(JSON.stringify(err)); self._prepareFinished(cb);            });}else{this._prepareFinished(cb);}},prepareFinished(cb){/*//初始化引擎,设置帧循环事件等等方法       this._initEngine();                this._setAnimFrame();.....↑↑↑↑↑↑↑↑至此已经完成了引擎的准备工作*///开始运行主循环this._runMainLoop();//派发EVENT_GAME_INITED事件this.emit(this.EVENT_GAME_INITED);},
}

由上可知,运行的顺序在cocos2d-js-min.js加载完之后执行main.js的windows.boot,传入配置调cc.game.run函数,然后注册配置信息 开始准备prepare,加载脚本初始化引擎,设置帧事件,调用_runMainLoop开始运行主循环。
ok,到运行主循环这里就开始接触到我们要探究的生命周期回调函数了,

//Run game. _runMainLoop: function () {        if (CC_EDITOR) { return;       }        if (!this._prepared) return;var self = this, callback, config = self.config,            director = cc.director,            skip = true, frameRate = config.frameRate;// 设置在左下角是否显示fps信息debug.setDisplayStats(config.showFPS);callback = function (now) { // 非暂停状态           if (!self._paused) {//requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘                self._intervalId = window.requestAnimFrame(callback);                if (!CC_JSB && !CC_RUNTIME && frameRate === 30) {    // 每2帧跳1帧执行                if (skip = !skip) {                       return;                    }                }  // 执行下一帧循环             director.mainLoop(now);            }        };self._intervalId = window.requestAnimFrame(callback);        self._paused = false;   },

可以看出,利用 window.requestAnimationFrame 及其回调函数来实现循环,循环里调用的是 director.mainLoop(),

//CCDirector.js
//在初始化时 有sharedInit: function () {        this._compScheduler = new ComponentScheduler();        this._nodeActivator = new NodeActivator();cc.loader.init(this);    },mainLoop (now) {       if (this._purgeDirectorInNextLoop) {        this._purgeDirectorInNextLoop = false;           this.purgeDirector();        } else {            // 计算全局的时间增量,即 dt  this.calculateDeltaTime(now);          if (!this._paused) {//每个帧的开始时所触发的事件                this.emit(cc.Director.EVENT_BEFORE_UPDATE);               // 对最新加入的组件调用 `start` 方法            this._compScheduler.startPhase();               // 调用组件的 `update` 方法                     this._compScheduler.updatePhase(this._deltaTime);               //调用调度器的 `update` 方法  this._scheduler.update(this._deltaTime);                // 调用组件的 `lateUpdate` 方法this._compScheduler.lateUpdatePhase(this._deltaTime);               // 将在引擎和组件 “update” 逻辑之后所触发的事件。              this.emit(cc.Director.EVENT_AFTER_UPDATE);               // 回收内存             Obj._deferredDestroy();           }// 访问渲染场景树之前所触发的事件。            this.emit(cc.Director.EVENT_BEFORE_DRAW);           renderer.render(this._scene, this._deltaTime);// 渲染过程之后所触发的事件            this.emit(cc.Director.EVENT_AFTER_DRAW);eventManager.frameUpdateListeners();            this._totalFrames++;       }   }, 

ok,看到这里我们已经大概很明确这些回调了,接下来我们在深入的看一下ComponentScheduler类和NodeActivator类具体函数的实现,我们以start简化源码为例来看一下

//component-scheduler.js function ctor(){//开始this.startInvoker = new OneOffInvoker(invokeStart);this.updateInvoker = new ReusableInvoker(invokeUpdate);this.lateUpdateInvoker = new ReusableInvoker(invokeLateUpdate);//下一帧组件方法数组this.scheduleInNextFrame = [];// 一次循环中this._updating = false;},var OneOffInvoker = cc.Class({extends: LifeCycleInvoker,//....//....invoke () {...})};var invokeStar =  function (iterator) {var array = iterator.array;for (iterator.i = 0; iterator.i < array.length; ++iterator.i) {let comp = array[iterator.i];//调用组件的 start 方法comp.start();comp._objFlags |= IsStartCalled;}},startPhase () { // 当前帧开始       this._updating = true;if (this.scheduleInNextFrame.length > 0) {            this._deferredSchedule();        }//调用 startInvoker   this.startInvoker.invoke();},

我们可以看到在外部调用startPhase 方法后,他会去判断上个循环是否结束,然后调用this.startInvoke,而他在构造函数中已经实现。update,onenable等生命周期回调方法都在这个脚本中实现,而在NodeActivator类中的activateComp方法的工作就是调用并只调用一次组件的 onLoad 方法。这里就不在描述

好了,至此,已经分析了creator提供给我们的这些生命周期回调方法的实现。如有遗漏或不足,还请多多指教

creator源码分析(生命周期函数回调相关)相关推荐

  1. LIRE原理与源码分析(二)——相关接口

    1. LIRE原理与源码分析(二)-- 代码结构 2. LIRE原理与源码分析(二)-- 相关接口 上一篇文章介绍了LIRE的基本内容和源码的代码结构.本文针对LIRE中主要的三个接口(LireFea ...

  2. Android Binder机制情景源码分析之Binder回调注册和反注册

    我们在日常开发中,经常用到Binder来进行跨进程通信,有个比较常见的场景是向服务端注册Binder回调,比如: IActivityManager中有两个成对的方法,Client端向AMS所在的服务端 ...

  3. motan源码分析五:cluster相关

    上一章我们分析了客户端调用服务端相关的源码,但是到了cluster里面的部分我们就没有分析了,本章将深入分析cluster和它的相关支持类. 1.clustersupport的创建过程,上一章的Ref ...

  4. Linux kernel 3.10内核源码分析--slab原理及相关代码

    1.基本原理 我们知道,Linux保护模式下,采用分页机制,内核中物理内存使用buddy system(伙伴系统)进行管理,管理的内存单元大小为一页,也就是说使用buddy system分配内存最少需 ...

  5. 源码分析工具Joern的相关资料整理

    随着对joern的了解,发现这个工具的潜能挺大的.但实际上手起来还是有点难度.这里列举一些对学习joern有帮助的相关资料博客. joern官方文档:https://docs.joern.io/ jo ...

  6. Vue.js 源码分析(九) 基础篇 生命周期详解

    先来看看官网的介绍: 主要有八个生命周期,分别是: beforeCreate.created.beforeMount.mounted.beforeupdate.updated   .beforeDes ...

  7. 详述 Spring MVC 启动流程及相关源码分析

    文章目录 Web 应用部署初始化过程(Web Application Deployement) Spring MVC 启动过程 Listener 的初始化过程 Filter 的初始化 Servlet ...

  8. Lifecycle 使用与源码分析——彻底搞懂Lifecycle原理

    一.Lifecycle 介绍 Lifecycle是一个生命周期感知组件,一般用来响应Activity.Fragment等组件的生命周期变化,并将变化通知到已注册的观察者.有助于更好地组织代码,让代码逻 ...

  9. Lifecycle 使用与源码分析

    一.Lifecycle 介绍 Lifecycle是一个生命周期感知组件,一般用来响应Activity.Fragment等组件的生命周期变化,并将变化通知到已注册的观察者.有助于更好地组织代码,让代码逻 ...

最新文章

  1. ISME:比较基因组学揭示蓝藻进化和生境适应性特征
  2. android surfaceview动画,怎么让android的surfaceview中的动画更加平滑流畅
  3. [转]ESP8266使用详解
  4. C++ STL学习之容器set和multiset (补充材料)
  5. ProE常用曲线方程:Python Matplotlib 版本代码(蝴蝶曲线)
  6. iOS音频的后台播放总结(后台网络请求歌曲,Remote控制,锁屏封面,各种打断)...
  7. 将pdf书籍变成横排的方法
  8. 5动态显示图片_单片机入门 数码管的静态显示和动态显示 壁纸
  9. linux发布微软消息队列,消息队列RabbitMQ入门与5种模式详解
  10. apache缺省banner_NSFOCUS建议您采取以下措施以降低威胁: * 修改源代码或者配置文件改变SSH服务的缺省banner。...
  11. 四、基于TCP的服务器端/客户端
  12. 基于springboot的简易聊天系统
  13. 阶段3 1.Mybatis_01.Mybatis课程介绍及环境搭建_01.mybatis课程介绍
  14. sql:mysql:数据库优化
  15. 99%的人不知道大数据分析现状是什么,主要的分析技术是什么?
  16. sql日志的详细打印的配置
  17. 机器人鸣人是哪一集_博人传:佐良娜因爱开启二勾玉!迪帕是机器人,大蛇丸很怕鸣人?...
  18. 数据预处理+数据清理
  19. apache模块载入命令_Apache动态加载模块实例讲解
  20. python math.sinh_带有Python示例的math.sinh()方法

热门文章

  1. 《Protein Actions Principles and Modeling》-《蛋白质作用原理和建模》中文分享(6)
  2. “傻瓜”不是瓜,“肮脏”本不脏
  3. asp执行cmd实例
  4. python中单引号、双引号和三引号的区别
  5. 损失函数:Center Loss
  6. Android Studio中有关R类地问题
  7. 【bzoj4300】绝世好题
  8. 【C#窗体登录界面的一些问题和方法】
  9. 修改form重定到iframe中,模拟异步上传文件的效果
  10. 机会网络仿真工具ONE.1.4.1使用说明