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

本文详细介绍了Egret 2D游戏引擎从runEgret函数开始的启动过程,包括播放器创建、舞台与渲染缓冲的建立、系统ticker的更新以及滑动跑道模型的渲染机制。核心内容包括WebPlayer的初始化、DisplayObject的更新和渲染流程,揭示了引擎如何管理每帧更新和渲染的主要步骤。
摘要由CSDN通过智能技术生成

本帖最后由 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

c999a7b2d0915dba47116c3294ea76a8.giflayer):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的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值