【三】CocosCreator-CCDirector.js源码分析
PS:只是看源码学习过程中把认为重要的内容以笔记的形式记录下来。
【1】cc.director:cc.Director的一个单例对象。
????????如果需要用到导演类的内容,统一通过cc.director这个单例对象来调用。
【2】init():对导演类的成员变量进行初始化操作。
????????在构造函数对此init函数注册了消息监听,当接收到来自CCGame的EVENT_ENGINE_INITED事件后才执行导演类的init函数。
? ? ? ? 在init里面会new大量的manager,动作管理器、事件管理器、动画管理器、物理管理器、3D物理管理器等,并且设置他们的scheduleUpdate,所以这些manager的update函数就是从这里设置的了。这些new出来的管理器通过成员变量保存下来了,所以如果通过导演类这个单例去调用这些管理器,这些管理器也成为单例使用了。
【3】calculateDeltaTime():用于计算每次update的时间差。
????????每次游戏的主循环都会调用这个函数,用于计算这次update与上次update的时间差,保存到this._deltaTime当中,在主循环内调用update时作为参数传递过去。 我们平时常用的update(dt)的dt时间差就是这样产生的了。
????????
【4】convertToGL():把屏幕坐标转成webGL坐标
【5】convertToUI():把webGL坐标转成屏幕对应坐标
【6】end():关闭导演类。
? ? ? ? 此方法只是设置了一个布尔值,等下一次主循环时才真正调用purgeDirector函数来关闭导演类,purgeDirector内部会清空_scheduler和_compScheduler、停止事件管理器、烧毁当前场景、清理renderer,清理内建资源、暂停game的主循环、重置资源管理器。
【7】getWinSize()和getWinSizeInPixels():获取视图大小
? ? ? ? 两个方法内部实则都是通过cc.winSize获取大小……如果需要获取分辨率应该使用cc.view.getFrameSize()
【8】_paused:暂停游戏逻辑
? ? ? ? 与game的_paused不同,导演类的_paused只会暂停游戏逻辑,不会暂停渲染、音频、事件等
【9】purgeCachedData():调用cc.assetManager.releaseAll()释放资源管理器内的所有资源。
【10】reset():重置导演类。
????????先调用purgeDirector()清除导演类的相关内容(在【6】里面说过),然后再重新设置各大管理器的scheduleUpdate,再调用game的resume()恢复主循环。
【11】runSceneImmediate():立即切换场景。具体流程如下:
1.scene._load():初始化scene
2.处理常驻节点:从game中拿出常驻节点数组,然后遍历数组,把所有的常驻节点的parent指向新的scene,如果新的scene里面已经包含了与常驻节点相同uuid的对象,则删除scene里面的node再把常驻节点的node加进scene里面来。
3.cc.assetManager._releaseManager._autoRelease():释放assetManager里面oldScene的资源。
4.oldScene.destroy():销毁oldScene。
5.onBeforeLoadScene():处理切换scene之前需要处理的内容。
6.scene._activate():激活节点。
7.cc.game.resume():恢复主循环
8.onLaunched(null, scene); 加载完成场景后的时间回调
PS:切换scene前和后都有对应的消息推送,我们只需监听对应的事件即可收到对应消息并处理我们想要处理的逻辑。
【12】runScene():运行指定的场景。
? ? ? ? 大致就是在当前帧绘制结束后调用【11】runSceneImmediate()来进行场景切换。
【13】loadScene():通过场景的名字来加载场景。
? ? ? ? 在assetManager里面通过场景名字来查找对应的bundle,如果有对应的bundle,就通过bundle.loadScene来加载场景,顺利获得scene后再调用【11】runSceneImmediate()来进行场景切换。
【14】preloadScene():预加载场景
? ? ? ? 通过assetManger来查找bundle,找到后调用bundle.preloadScene来预加载场景资源。
【15】setDepthTest():是否开启深度测试。
? ? ? ? 开启深度测试后,会把深度信息存贮在一个深度缓冲中,在进行渲染时,会从深度缓冲获取Z值进行比较,把最靠近屏幕的片段保存下来,其他片段则会被丢弃(简单来讲就是显示最前面的,后面被前面挡住那些反正看不到,就把他丢弃掉得了)。
扩展延伸-深度冲突:当两个平面或者三角形非常非常接近的时候,深度缓冲精度不足导致判断不了两个三角形哪个在前面时,两个三角形就会不断变换前后顺序导致最后出来奇怪的花纹。解决方案:1.别把两个物体摆太靠近……2.牺牲性能用更高精度的缓冲区…… 个人喜欢方案1,当物体太靠近时,我们人工设置一点偏移值让其避免深度冲突。
【16】_scene:当前正在运行的场景。
getScene()和getRuningScene()在源码里都是返回这个值。
【17】_deltaTime:上一帧和当前帧的时间差。
【18】_startTime:游戏开始的时间(导演类init的时间)
【19】_totalFrames:游戏启动以来运行的总帧数(在每一次主循环+1)
【20】_scheduler:定时器对象,在这里面设置了各大管理器的update。
【21】startAnimation()和stopAnimation():其实调用的是game的pause,暂停主循环。
【22】mainLoop:主循环。具体流程如下(只讨论正式模式下):
1.执行上面说到的【4】,检测布尔值,如果为true则清理导演类
2.this.calculateDeltaTime(now);:计算dt
3.this._compScheduler.startPhase();:执行start函数(component-scheduler.js内部保证start只执行一次)
4.this._compScheduler.updatePhase(this._deltaTime);:执行update函数。
5.this._scheduler.update(this._deltaTime);执行各大管理器的update函数。
6.this._compScheduler.lateUpdatePhase(this._deltaTime);:执行lateUpdate函数。
PS:3,4,6三个步骤也可以看出这3个生命周期函数的执行顺序。
7.Obj._deferredDestroy();:销毁被移除的实体。
8.renderer.render(this._scene, this._deltaTime);:渲染场景
9.eventManager.frameUpdateListeners();:更新事件处理器,检测是否有新的监听需要增加或者有旧的监听需要移除。
10.this._totalFrames++;:总帧数+1
以上过程中间涉及到某些步骤的消息分发,此处跳过不提了……需要用到时去看看有什么相关消息可以监听即可。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!