class rkuk implements ActionScript

我的ActionScript小路

« TweenLite源码剖析3TweenLite源码剖析5 »

TweenLite源码剖析4

上一篇中TweenLite已经建立完成,接下来就要开始渲染了。在TweenLite tool中所有TweenCore对象(包括TweenLite、TweenMax、TimelineLite、TimelineMax以及root时间线对应的类SimpleTimeline)的渲染方法都是renderTime,这里体现了按接口设计的原则,也就是告诉对象要做什么,但是具体怎么做就由对象自己实现。再说具体点就是渲染发生的时候只通知对象调用renderTime方法,但renderTime方法内执行些什么,就由TweenLite、TweenMax、TimelineLite、TimelineMax和SimpleTimeline自己负责实现。这5个类的renderTime方法的具体实现各不相同,但也有近似的地方,可以划分为两种类型:第一种是Tween类的renderTime(包括TweenLite、TweenMax),另一种是时间线的类的renderTime(包括TimelineLite、TimelineMax和SimpleTimeline)。概括的说:第一种类型的renderTime主要实现操作target的属性更新,第二种类型的renderTime主要实现通知包含在该时间线上的TweenCore对象进行渲染。

前面说过TweenLite.updateAll方法是整个渲染过程的起点,所以这里先从这个起点开始。在TweenLite.updateAll中调用了root时间线的renderTime方法。每次渲染都是由root时间线的renderTime发起的,root时间线是一个SimpleTimeline对象,这里就先说说最简单的SimpleTimeline渲染。

SimpleTimeline不是给TweenLite tool的用户使用的,其作用就是作为root时间线,持续不断的对添加到其上的对象进行渲染,这里强调持续不断是因为即使root时间线上没有任何Tween,root时间线的renderTime仍然在每个EnterFrame时都执行,就相当于root时间线上的播放头一直在播放,而root时间线上播放头对应的时间也在持续增加,这也是前面把root时间线称为绝对基准时间线的原因。与用户创建TimelineLite和TimelineMax时间线不同,用户创建的时间线并不会持续不断的渲染(用户时间线全部走完之后就会被删除),用户时间线上播放头对应的时间也并不是总在增大(当reverse的时候就在减小),在后面剖析TimelineLite和TimelineMax时再详细说明。先来到SimpleTimeline.renderTime方法中: 

SimpleTimeline.renderTime方法 [复制代码]
  1. var tween:TweenCore = _firstChild, dur:Number, next:TweenCore;
  2. this.cachedTotalTime = time;
  3. this.cachedTime = time;
  4. while (tween) {
  5.     next = tween.nextNode;
  6.     if (tween.active || (time >= tween.cachedStartTime && !tween.cachedPaused)) {
  7.         if (!tween.cachedReversed) {
  8.             tween.renderTime((time - tween.cachedStartTime) * tween.cachedTimeScale, suppressEvents, false);
  9.         } else {
  10.             dur = (tween.cacheIsDirty) ? tween.totalDuration : tween.cachedTotalDuration;
  11.             tween.renderTime(dur - ((time - tween.cachedStartTime) * tween.cachedTimeScale), suppressEvents, false);
  12.         }
  13.     }
  14.     tween = next;
  15. }

 前面提到时间线渲染的本质就是通知包含在该时间线上的TweenCore对象自己进行渲染,也就是调用TweenCore自身的renderTime。那么在调用前,root时间线要找到有哪些TweenCore对象添加到了自身,找到children的这个过程是通过链表的方式实现的,也就是root时间线先找到第一个TweenCore,而第一个TweenCore会有一个链接到下一个TweenCore的属性,第二个又链接到第三个,一直依次链接到最后一个被添加到root时间线的TweenCore对象。那么这个链表是在什么时候形成的呢?这就需要回到TweenCore的构造函数中,前面讲TweenCore构造函数的时候说到每个TweenCore对象在创建时会被添加到某条时间线上,当用户在创建TweenCore时没有指定时间线时,就默认添加到root时间线,这个过程是: 

TweenLite被添加到root时间线上 [复制代码]
  1. var tl:SimpleTimeline = (this.vars.timeline is SimpleTimeline) ? this.vars.timeline : (this.vars.useFrames) ? TweenLite.rootFramesTimeline : TweenLite.rootTimeline;
  2. this.cachedStartTime = tl.cachedTotalTime + _delay;
  3. tl.addChild(this)

当没有指定时间线时,tl就引用root时间线,会调用SimpleTimeline的addChild方法,SimpleTimeline.renderTime执行的内容如下:

SimpleTimeline.addChild方法 [复制代码]
  1. if (!tween.gc && tween.timeline) {
  2.     tween.timeline.remove(tween, true);
  3. }
  4. tween.timeline = this;
  5. if (tween.gc) {
  6.     tween.setEnabled(true, true);
  7. }
  8. if (_firstChild) {
  9.     _firstChild.prevNode = tween;
  10. }
  11. tween.nextNode = _firstChild;
  12. _firstChild = tween;
  13. tween.prevNode = null;

 这个过程中首先检查被添加的tween是否已经被添加到其它时间线上,如果是则先要从原来的时间线上移除后,再添加到现在的SimpleTimeline上。添加的过程就是让被添加的tween形成链表的过程,在SimpleTimeline中,后添加的tween会被放到链表的最前面,由SimpleTimeline的_firstChild引用,所以后添加的tween在渲染的时候会先被渲染(这与TimelineLite和TimelineMax不同),这样的顺序在特定的时候会影响多个作用于同一个target的Tween之间的overwrite。

再回到SimpleTimeline.renderTime中,渲染开始前获得时间线的_firstChild之后,在刷新当前时间线线播放头对应的时间,也就是this.cachedTotalTime和this.cachedTime。在SimpleTimeline中这两个属性始终是相等的。这里需要注意:当前时间线播放头对应的时间,其本质是本条时间线的父级时间线的时间相对于本条时间线起点时间之间经历的时间长度,这个定义同样适用于TweenLite、TweenMax、TimelineLite和TimelineMax(root时间线的timeline属性为null,但从updateAll 中可以看到,root时间线的父级时间线相当于是flash播放器自身的时间,也就是从getTimer获取的时间)。TweenLite tool之所以这样设计,是因为这样能够实现从一个绝对基准时间(也就是root时间线的时间)形成多个TweenCore对象自身独立的时间。稍后对这个渲染事件进行具体说明。

接着看SimpleTimeline中刷新完当前渲染时间后,就开始用一个while循环,通知root时间线上的所有tween链表开始执行其自身的渲染。每个tween是否执行渲染还有一个判断条件如下:

TweenLite开始渲染的条件 [复制代码]
  1. if (tween.active || (time >= tween.cachedStartTime && !tween.cachedPaused)

先看这个条件“||”操作之后的部分,是检测root时间线当前的渲染时间是否大于等于tween的启动时间,并且tween是否被暂停。这个条件说明必须等到tween所处的时间线的播放头必须到达tween的启动时间之后,并且tween没有被暂停,那么才能让tween渲染,在未到启动时间之前或者tween被暂停了,那么就不用渲染这个tween。这个条件保证了tween能够在正确的时间启动,并且能够被暂停。在tween渲染的过程中会把tween.ative设为true,这样表示tween已经激活,那么下次渲染时机再到来的时候,就只检查tween是否被激活,而不用在检查tween是否已经启动,因此这个条件在“||”之前先检查active是为了不哟个反复检查tween已经开始启动,这样可以提高执行效率。当然tween在执行完成之后或者被暂停的时候,也就会同时把active设为为false,以避免不应该有的渲染。

满足渲染条件之后,还要检查tween.cachedReversed标志,当标志位false时表示tween在正向运行,标志为true时表示tween在反向运行。(正向运行表示将target从起始状态变换到终点状态,反向运行表示将target从终点状态变换到起点状态,这里提到的tween起点状态和终点状态时在创建tween的时候设置的,注意起始状态和终点状态在创建tween的时候只完成设置,但并没有确定,实际确定tween的起始状态和终点状态时在初始化的时候,在TweenLite.renderTime中再做说明)。根据tween的运行方向,root时间线会告诉tween应该渲染什么时刻的状态,正向运行的时候:

TweenLite正向运行时的渲染 [复制代码]
  1. tween.renderTime((time - tween.cachedStartTime) * tween.cachedTimeScale, suppressEvents, false);

root时间线告诉tween渲染(time - tween.cachedStartTime)* tween.cachedTimeScale时刻的状态。这个渲染时刻表示的意义就是刚才对渲染时刻的解释:即tween的的渲染时间是tween的父级时间线的时间相对于tween的起点时间之间经历的时间长度,这里也印证了前面所说的“TweenLite对象的启动时间cachedStartTime是相对于其parent时间线而言的”。这样处理后,等进入了tween.renderTime方法中,那么tween就相当于有了一个属于自身的独立时间。tween.cachedTimeScale起的作用就是对渲染时间进行缩放,达到Tween变换过程中加速和减速的效果。从这里可以看出,当root时间线的时间time不改变的时候,如果改变tween.cachedStartTime,那么tween就会渲染不同的状态。TweenLite tool就是基于这个原理,实现在不改变parent时间线时间的前提下,让Tween过程前进、后退或反向的。tween反向运行的时候,计算渲染时间要复杂一些,到reverse方法的时候再作说明。
 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Copyright © 2008 www.rkuk.org, All Rights Reserved.

Powered By Z-Blog 1.8 Arwen Build 90619