本帖最后由 fightingcat 于 2016-7-16 00:26 编辑

上一篇讲到了引擎的入口runEgret为每一个播放器标签(就是index.html中看到的那个

之前web.WebPlayer初始化时调用了sys.Player的start方法:

[mw_shl_code=actionscript3,true]

/**

* @private

* 启动播放器

*/

public start():void {

/// ……

if (!this.root) {

this.initialize();

}

$ticker.$addPlayer(this);

}

[/mw_shl_code]

root声明的类型是DisplayObject,如果root未设置,就调用initialize初始化:

[mw_shl_code=actionscript3,true]

private initialize():void {

var rootClass;

if (this.entryClassName) {

rootClass = egret.getDefinitionByName(this.entryClassName);

}

if (rootClass) {

var rootContainer:any = new rootClass();

this.root = rootContainer;

if (rootContainer instanceof egret.DisplayObject) {

this.stage.addChild(rootContainer);

}

DEBUG && $error(1002, this.entryClassName);

}

}

else {

DEBUG && $error(1001, this.entryClassName);

}

}

[/mw_shl_code]

这里就是根据index.html中播放器标签的data-entry-class属性指定的类名获取入口类,创建一个对象并作为sys.Player的root节点,然后加入stage的子节点中。

初始化完后调用了$ticker.$addPlayer(this)注册并运行播放器。这里再一次用到了sys.$ticker,前面说过它是sys.SystemTicker的单例。事实上除了驱动sys.Player,sys.SystemTicker管理了所有需要循环更新的逻辑,以及广播ENTERFRAME事件,无论是egret.setTimeout还是Tween都使用了sys.SystemTicker来注册每帧更新事件。

源码位于 egret/player/SystemTicker.ts 中:

[mw_shl_code=actionscript3,true]

/**

* @private

* 注册一个播放器实例并运行

*/

$addPlayer(player

layer):void {

if (this.playerList.indexOf(player) != -1) {

return;

}

if (DEBUG) {

egret_stages.push(player.stage);

}

this.playerList = this.playerList.concat();

this.playerList.push(player);

}

[/mw_shl_code]

只是把sys.Player加入到列表中(不知为何用concat复制了个新的列表),那么sys.SystemTicker是如何驱动sys.Player运行的呢?还记得前面第一次用到$ticker是在引擎的入口runEgret()里吧,其中启动了一个循环不断调用$ticker.update,所以接下来看sys.SystemTicker的update方法:

[mw_shl_code=actionscript3,true]

public update():void {

var t1 = egret.getTimer();

var timeStamp = egret.getTimer();

for (var i = 0; i < this.callBackList.length; i++) {

if (this.callBackList.call(this.thisObjectList, timeStamp)) {

$requestRenderingFlag = true;

}

}

/// 接下

[/mw_shl_code]

这里遍历了一个callBackList并执行其中的回调函数,这个列表就是除了播放器外,其他逻辑注册的更新事件(见$startTick方法)。如果回调函数返回true,则表示需要立即触发渲染,$requestRenderingFlag是egret.sys命名空间下的公共变量,控制后面是否执行渲染逻辑。(code review技巧:在wing3.x或者vscode中选中一个符号(变量、属性、方法或类)并按shift+F12可以查看使用到这个符号的代码,可以自己看一下都有哪些功能注册了这个事件回调。)

[mw_shl_code=actionscript3,true]

/// 接上

this.lastCount -= 1000;

var t2 = egret.getTimer();

if (this.lastCount > 0) {

if ($requestRenderingFlag) {

this.render(false, this.costEnterFrame + t2 - t1);

}

return;

}

this.lastCount += this.frameInterval;

this.render(true, this.costEnterFrame + t2 - t1);

var t3 = egret.getTimer();

this.broadcastEnterFrame();

var t4 = egret.getTimer();

this.costEnterFrame = t4 - t3;

}

[/mw_shl_code]

代码稍微简化了一下,去掉了一些不必要的局部变量(个人觉得这种优化有限却降低可读性)。

这里的变量命名不是很好,frameInterval是指以60帧为基准相对当前帧率的倍数(因为runEgret中的循环是以60帧为准的,这里相当于跳帧处理),lastCount是一个计数器,初始为frameInterval,每次减1,当大于0时说明需要跳帧,但如果$requestRenderingFlag为真就调用this.render方法主动渲染一次。否则(lastCount<=0),说明发生了跳帧,lastCount再加上frameInterval。为了消除误差,涉及的量都乘以了1000,所以这里lastCount是-1000而不是1,frameInterval也是大于1000的整数。大概这就是egret所谓的滑动跑道模型吧,其实并没有什么高深的……

再来看$render方法(省略了一些调试相关的代码):

[mw_shl_code=actionscript3,true]

$render(triggerByFrame: boolean, costTicker: number): void {

this.callLaters();

this.callLaterAsyncs();

var dirtyList = this.stage.$displayList.updateDirtyRegions();

var drawCalls = this.stage.$displayList.drawToSurface();

/// 调试相关

}

[/mw_shl_code]

这里先调用了两个方法:callLaters和callLaterAsyncs,作用就是执行egret/player/utils/callLater.ts中callLater和$callAsync注册的延迟回调,从实现上看这两个方法完全一样,除了后者注释为私有,可能是考虑语义上的区分。另外其中有释放和创建数组的操作,不过由于对象生命周期很短可能并不会影响性能。

后面两句看函数名就可以知道,分别是更新舞台显示列表的脏区域,以及绘制舞台显示列表到sys.RenderBuffer。之前跳过了sys.DisplayList,接下来就可以分析sys.DisplayList的实现了。

小结,egret引擎启动流程

引擎从runEgret函数开始启动,先启动一个60帧每秒的循环,并调用sys.$ticker.update(),sys.$ticker是sys.SystemTicker的单例对象,负责管理所有每帧回调。

然后遍历页面上所有拥有"egret-class"CSS类的标签,并为其创建web.WebPlayer。

web.WebPlayer初始化监听用户输入事件,创建Stage和sys.RenderBuffer(实际的实现是web.CanvasRenderBuffer或web.WebGLRenderBuffer)。

web.WebPlayer把创建的RenderBuffer的canvas加入播放器标签,并设置基本的CSS属性。

web.WebPlayer用上一步创建的Stage和sys.RenderBuffer创建sys.Player,并调用其start方法启动播放器。

sys.Player在start中初始化,根据传入的选项创建主类(通常是Main),设置为播放器的根节点,并加入舞台。

sys.Player在start中初始化完毕,调用 sys.SystemTicker(通过单例sys.$ticker)的$addPlayer方法注册播放器。

sys.SystemTicker在update中处理每帧更新回调,并通过滑动跑道的方式调用所有sys.Player实例的render方法。

sys.Player在render中执行延迟回调,更新Stage的显示列表的脏区域,绘制Stage的显示列表到sys.RenderBuffer。

以上就是egret 2D引擎(Web)从启动、创建播放器到驱动播放器更新和渲染的流程框架。下一篇开始分析显示列表是如何更新和渲染DisplayObject的。

白鹭php源码,egret 2D引擎源码分析(二) 创建播放器相关推荐

  1. 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇...

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  2. 【Android FFMPEG 开发】OpenSLES 播放音频 ( 创建引擎 | 输出混音设置 | 配置输入输出 | 创建播放器 | 获取播放/队列接口 | 回调函数 | 开始播放 | 激活回调 )

    文章目录 I . FFMPEG 播放视频流程 II . OpenSLES 播放音频流程 III . OpenSLES 播放参考 Google 官方示例 IV . OpenSL ES 播放代码 ( 详细 ...

  3. ios网易云音乐源码、动画引擎源码等

    iOS精选源码 自己维护的框架, 超级多功能 图片选择SDK:支持多选,相册选择,预览,网络图预览 一款可以简单实现长按拖拽重排的 UICellCollectionView Cell框... 动画引擎 ...

  4. 支持Unity引擎!Visbit推出Web VR播放器云服务

    Visbit实现了VR视频云服务在移动端的全面覆盖. 据悉,Visbit网页端VR播放器基于Web VR开发,并推出VR开发引擎Unity的SDK.要知道,四大主流浏览器Chrome.Firefox. ...

  5. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java杨佑川音乐播放器908v6

    大部分步骤是 1.确定选题 选题的确定需要查阅大量的资料,要搞清楚自己大概想要研究的方向是什么.可以选择自己感兴趣的学科或者强势的学科进行研究,同时要多和毕业指导老师多交流,征求老师的意见和建议,最后 ...

  6. 明月浩空播放器php源码,【Emlog插件】明月浩空音乐播放器

    [摘要] 资源简介:明月浩空-Html5浮窗音乐播放器是基于QQ音乐.酷狗音乐.网易云音乐等歌曲ID全自动解析的Html5音乐播放器程序依靠服务器强大的接口功能,只需要一个歌曲... 资源简介: 明月 ...

  7. Google原生输入法LatinIME引擎初始化流程分析(二)

    引擎初始化首先是在Java层调用native的初始化方法,Java层调用如下: private void initPinyinEngine() {byte usr_dict[];usr_dict = ...

  8. 2022-10-24 ClickHouse 源码解析-查询引擎经典理论

    ClickHouse 源码解析: 综述 ClickHouse 源码解析: MergeTree Write-Path ClickHouse 源码解析: MergeTree Read-Path Click ...

  9. Android视频直播源码开发直播平台、点播播放器哪家强?

    Android视频直播源码开发直播平台.点播播放器哪家强? 最近在项目中要加入视频直播和点播功能,那么问题来了,我需要一个播放器来播放视频流,那该如何选择呢?除了原生的VideoView(VideoV ...

最新文章

  1. 不用Office自动化技术,给Word文档中填充赋值
  2. python基础知识点-Python入门基础知识点(基础语法介绍)
  3. Modular_exponentiation模幂运算
  4. 2.1 0/1分类问题-机器学习笔记-斯坦福吴恩达教授
  5. boost::fusion::find_if用法的测试程序
  6. getSerializableExtra
  7. 武汉.NET俱乐部12月活动图片及课件下载
  8. 何为领导力 —— 《Working Backwards》书评
  9. BCH码(BCH code)详细分析
  10. 如何在word中的图片上画圈标注_word文字下怎么画圈标记
  11. HTML5期末大作业:直播网站设计——仿在线媒体歪秀直播官网模板html源码(11个页面) HTML+CSS+JavaScript 期末作业HTML代码...
  12. Android_Provision
  13. 实现阿里云视频直播流程
  14. 说话人性别识别——语音检测初探
  15. java 获取流 丢失_java文件流数据丢失问题
  16. jdk14下载与安装教程(win10)超详细
  17. AVFI Carla安装踩坑记录
  18. 默哀STAND SILENTLY!
  19. dxf geojson 转换,如何将CAD(DWG)文件转换为GeoJSON?
  20. 锂电池的六个主要参数

热门文章

  1. win32 中GetLastError 关于code与信息
  2. 7人制足球技战术要点
  3. CPU温度过高有什么影响
  4. 夏天CPU温度过高原因及解决办法
  5. ide模式ahci模式_IDE的完整形式是什么?
  6. 鲲鹏、昇腾、欧拉——计算产业的矩阵已足够宽广
  7. Android App包瘦身优化
  8. Linux信号:SIGCHLD信号和僵尸进程
  9. 环境变量的作用及设置方法
  10. 51nod_1000