xiangpei001
Flash/Flex构架师 / 广东
积分 0

as3.0中的Tween类,flash缓冲效果讲解


2010-08-27 点击:


最近做的东西,对于效果编程比较多,特别是缓冲,加速度等效果,特意研究了一下Tween类,写篇教程分享给大家,算是过年送给大家的新年礼物!

下面是官方写的fl.transitions.Tween类:
可以先尝试看一下这段代码的写法,用这个方法去看:
从构造函数看起,假设我使用了该类
new Tween(mc,"x",Regular.easeOut,0,200,4);
结合adobe的帮助文档,当初始化实例的时候,便对对象mc的x进行Regular.easeOut操作,具体是从0值到200值,历时4帧
然后问一个为什么,他为什么会对对象mc的x进行Regular.easeOut操作,具体是从0值到200值,历时4帧?
带着这个问题,现在开始看这个类吧!从构造函数看
 

  1. package fl.transitions  
  2. {  
  3. import flash.events.*;  
  4. import flash.display.*;  
  5. import flash.utils.*;  
  6. [Event(name="motionChange"type="fl.transitions.TweenEvent")]  
  7. [Event(name="motionFinish"type="fl.transitions.TweenEvent")]  
  8. [Event(name="motionLoop"type="fl.transitions.TweenEvent")]  
  9. [Event(name="motionResume"type="fl.transitions.TweenEvent")]  
  10. [Event(name="motionStart"type="fl.transitions.TweenEvent")]  
  11. [Event(name="motionStop"type="fl.transitions.TweenEvent")]  
  12. public class Tween extends EventDispatcher  
  13. {  
  14.    protected static var _mc:MovieClip = new MovieClip();  
  15.  
  16.   public var isPlaying:Boolean = false;  
  17.  
  18.    public var obj:Object = null;  
  19.  
  20.   public var prop:String = "";  
  21.  
  22.   public var func:Function = function (t:Number, b:Number, c:Number, d:Number):Number { return c*t/d + b; }  
  23.  
  24.   public var begin:Number = NaN;  
  25.  
  26.   public var change:Number = NaN;  
  27.  
  28.   public var useSeconds:Boolean = false;  
  29.  
  30.   public var prevTime:Number = NaN;  
  31.  
  32.   public var prevPos:Number = NaN;  
  33.  
  34.   public var looping:Boolean = false;  
  35.  
  36.   private var _duration:Number = NaN;  
  37.  
  38.   private var _time:Number = NaN;  
  39.  
  40.   private var _fps:Number = NaN;  
  41.  
  42.   private var _position:Number = NaN;  
  43.  
  44.   private var _startTime:Number = NaN;  
  45.  
  46.   private var _intervalID:uint = 0;  
  47.  
  48.   private var _finish:Number = NaN;  
  49.  
  50.   private var _timer:Timer = null;  
  51.  
  52.  public function get time():Number   
  53.  {  
  54.  return this._time;  
  55.  }  
  56.  
  57.   public function set time(t:Number):void   
  58.   {  
  59.     thisthis.prevTime = this._time;  
  60.     if (t > this.duration) {  
  61.       if (this.looping) {  
  62.         this.rewind (t - this._duration);  
  63.         this.update();  
  64.         this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_LOOP, this._time, this._position));  
  65.       } else {  
  66.         if (this.useSeconds) {  
  67.           thisthis._time = this._duration;  
  68.           this.update();  
  69.         }  
  70.         this.stop();  
  71.         this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_FINISH, this._time, this._position));  
  72.       }  
  73.     } else if (t < 0) {  
  74.       this.rewind();  
  75.       this.update();  
  76.     } else {  
  77.       tthis._time = t;  
  78.       this.update();  
  79.     }  
  80.   }  
  81.  
  82.  public function get duration():Number   
  83.  {  
  84.  return this._duration;  
  85.  }  
  86.    
  87.   public function set duration(d:Number):void   
  88.   {  
  89.     this._duration = (d <= 0) ? Infinity : d;  
  90.   }  
  91.  
  92.  public function get FPS():Number   
  93.  {  
  94.  return this._fps;  
  95.  }  
  96.    
  97.   public function set FPS(fps:Number):void   
  98.   {  
  99.     var oldIsPlaying:Boolean = this.isPlaying;  
  100.     this.stopEnterFrame();  
  101.     this._fps = fps;  
  102.     if (oldIsPlaying)   
  103.     {  
  104.       this.startEnterFrame();  
  105.     }  
  106.   }  
  107.  
  108.  public function get position():Number   
  109.  {  
  110.  return this.getPosition(this._time);  
  111.  }  
  112.    
  113.   public function set position(p:Number):void   
  114.   {  
  115.     this.setPosition (p);  
  116.   }  
  117.    
  118.  public function getPosition(t:Number=NaN):Number   
  119.  {  
  120.  if (isNaN(t)) t = this._time;  
  121.  return this.func (t, this.begin, this.change, this._duration);  
  122.  }  
  123.  
  124.   public function setPosition(p:Number):void   
  125.   {  
  126.     thisthis.prevPos = this._position;  
  127.     if (this.prop.length)  
  128.       this.obj[this.prop] = this._position = p;  
  129.     this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_CHANGE, this._time, this._position));    
  130.   }  
  131.  
  132.  public function get finish():Number   
  133.  {  
  134.  return this.begin + this.change;  
  135.  }  
  136.    
  137.   public function set finish(value:Number):void   
  138.   {  
  139.     this.change = value - this.begin;  
  140.   }  
  141.     
  142.   function Tween(obj:Object, prop:String, func:Function, begin:Number, finish:Number, duration:Number, useSeconds:Boolean=false)   
  143.   {  
  144.     if (!arguments.length) return;  
  145.     this.obj = obj;  
  146.     this.prop = prop;  
  147.     this.begin = begin;  
  148.     this.position = begin;  
  149.     this.duration = duration;  
  150.     this.useSeconds = useSeconds;  
  151.     if (func is Function) this.func = func;  
  152.     this.finish = finish;  
  153.     this._timer = new Timer(100);  
  154.     this.start();  
  155.   }  
  156.  
  157.   public function continueTo(finish:Number, duration:Number):void {  
  158.     thisthis.begin = this.position;  
  159.     this.finish = finish;  
  160.     if (!isNaN(duration))  
  161.       this.duration = duration;  
  162.     this.start();  
  163.   }  
  164.     
  165.   public function yoyo():void   
  166.   {  
  167.     this.continueTo(this.begin, this.time);  
  168.   }  
  169.  
  170.   protected function startEnterFrame():void   
  171.   {  
  172.     if (isNaN(this._fps))   
  173.     {  
  174.       _mc.addEventListener(Event.ENTER_FRAME, this.onEnterFrame, false, 0, true);  
  175.     }   
  176.     else   
  177.     {  
  178.       var milliseconds:Number = 1000 / this._fps;  
  179.       this._timer.delay = milliseconds;  
  180.  this._timer.addEventListener(TimerEvent.TIMER, this.timerHandler, false, 0, true);  
  181.  this._timer.start();  
  182.     }  
  183.     this.isPlaying = true;  
  184.   }  
  185.  
  186.   protected function stopEnterFrame():void   
  187.   {  
  188.     if (isNaN(this._fps))   
  189.     {  
  190.       _mc.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);  
  191.     }   
  192.     else   
  193.     {  
  194.       this._timer.stop();  
  195.     }  
  196.     this.isPlaying = false;  
  197.   }  
  198.    
  199.   public function start():void   
  200.   {  
  201.     this.rewind();  
  202.     this.startEnterFrame();  
  203.     this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_START, this._time, this._position));  
  204.   }  
  205.    
  206.   public function stop():void   
  207.   {  
  208.     this.stopEnterFrame();  
  209.     this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_STOP, this._time, this._position));  
  210.   }  
  211.  
  212.   public function resume():void   
  213.   {  
  214.     this.fixTime();  
  215.     this.startEnterFrame();  
  216.     this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_RESUME, this._time, this._position));  
  217.   }  
  218.    
  219.   public function rewind(t:Number=0):void   
  220.   {  
  221.     tthis._time = t;  
  222.     this.fixTime();  
  223.     this.update();   
  224.   }  
  225.    
  226.   public function fforward():void   
  227.   {  
  228.     thisthis.time = this._duration;  
  229.     this.fixTime();  
  230.   }  
  231.    
  232.   public function nextFrame():void   
  233.   {  
  234.     if (this.useSeconds)   
  235.       this.time = (getTimer() - this._startTime) / 1000;  
  236.     else   
  237.       thisthis.time = this._time + 1;  
  238.   }  
  239.  
  240.   protected function onEnterFrame(event:Event):void   
  241.   {  
  242.     this.nextFrame();  
  243.   }  
  244.  
  245.   protected function timerHandler(timerEvent:TimerEvent):void   
  246.   {  
  247.     this.nextFrame();  
  248.     timerEvent.updateAfterEvent();  
  249.   }  
  250.  
  251.   public function prevFrame():void   
  252.   {  
  253.     if (!this.useSeconds) thisthis.time = this._time - 1;  
  254.   }  
  255.     
  256.   private function fixTime():void   
  257.   {  
  258.     if (this.useSeconds)   
  259.       this._startTime = getTimer() - this._time*1000;  
  260.   }  
  261.  
  262.   private function update():void   
  263.   {  
  264.     this.setPosition(this.getPosition(this._time));  
  265.   }  
  266.     
  267. }  
  268. }  
  269.  

不知大家看的如何,反正我现在来告诉你结果,你会发现,实际这个类很简单,他就做了一件事,就是每个时间变化每个不同的状态,而具体怎么变的,谁看到了?比如加速度,弹簧效果等都应该有算法,但是这里面并没有看到算法啊,只看到他每次更改时间time不管如何,总会update()一下,算法就在这,它会调用getPosition方法,而该方法返回的值是this.func (t, this.begin, this.change, this._duration)(插播参数讲解,func的4个参数分别是,当前运动到的time值,初始值即构造函数中第4个参数,要改变的值即结束值减初始值,总时间即构造函数中第6个参数)func方法得到的就是变化一下time之后的物体值,而这个func就是构造函数中第三个参数 Regular.easeOut,这个参数是fl.transitions.easing包中的某个类的某个方法,如果使用方法,返回的值就是 return -c * (t /= d) * (t - 2) + b;这个就是缓冲算法,fl.transitions.easing包中还有很多不同移动效果的算法,比如弹簧,加速度等。竟然看到这里,大家都知道了 Tween只不过是调用这些算法的一个东西罢了,那么我们根据自我需求写一些简单的缓冲类,然后调用adobe的这些精髓算法呢?

先看看官方的算法源代码
adobe官方fl.transitions.easing.Regular类,源代码:
 

  1. package fl.transitions.easing  
  2. {  
  3.  
  4. public class Regular  
  5. {  
  6.  
  7.   public static function easeIn(t:Number, b:Number,  
  8.                  c:Number, d:Number):Number  
  9.   {  
  10.     return c * (t /= d) * t + b;  
  11.   }  
  12.  
  13.   public static function easeOut(t:Number, b:Number,  
  14.                  c:Number, d:Number):Number  
  15.   {  
  16.     return -c * (t /= d) * (t - 2) + b;  
  17.   }  
  18.  
  19.   public static function easeInOut(t:Number, b:Number,  
  20.                    c:Number, d:Number):Number  
  21.   {  
  22.     if ((t /= d / 2) < 1)  
  23.       return c / 2 * t * t + b;  
  24.  
  25.     return -c / 2 * ((--t) * (t - 2) - 1) + b;  
  26.   }  
  27. }  
  28.  
  29. }  
  30.  

接下来看看,我为了某个项目,赶时间写出来针对显示对象一个非常简单的缓冲类,然后调用了官方的fl.transitions.easing包中的算法 
 

  1. package index.item.pairBumping{  
  2.     
  3.   import flash.display.DisplayObject;  
  4.   import flash.events.Event;  
  5.   import flash.events.EventDispatcher;  
  6.     
  7.   public class Motion extends EventDispatcher{  
  8.       
  9.     private var _target:DisplayObject;  
  10.     private var proNum:Number;  
  11.     private var startNum:Number;  
  12.     private var endNum:Number;  
  13.     private var actionStr:String;  
  14.     private var num1:uint;  
  15.     private var num2:uint;  
  16.     private var func:Function;  

    
    //构造函数与Tween基本上一样,只不过没有按时间计算,只有按帧运动
    //每个参数所表示的值也是一样的,fun:Function传入的参数和Tween一样,使用官方的fl.transitions.easing包
   

  1. public function Motion(target:DisplayObject,str:*,fun:Function,_start:Number = 0,_end:Number = 1,_pro:Number = 4){  
  2.      actionStr = str;  
  3.      _target = target;  
  4.      proNum = _pro;  
  5.      startNum = _start;  
  6.      endNum = _end;  
  7.      funfunc = fun;  
  8.    }  

    
    //创建Motion实例化后,并没有立即播放得执行play才播放,当然播放完一次,也能使用play继续播放
   

  1.  public function play(){  
  2.       stop();  
  3.       num1 = 0;  
  4.       _target[actionStr] = startNum;  
  5.       _target.addEventListener(Event.ENTER_FRAME,fun1);  
  6.     }  
  7.       
  8.     //顺走所执行事件  
  9.     private function fun1(e:Event){  
  10.       var t = num1 ++;//当前运行时间  
  11.       var d = proNum;//总时间  
  12.       var b = startNum;//开始值  
  13.       var c = endNum - startNum;//要改变的值  
  14.       _target[actionStr] = func(t,b,c,d);//调用官方算法,并且传入4个参数,进行计算!  
  15.       if(t > d){//判断是否时间到了  
  16.         stop();//ok,播放完毕,那么我们停止吧  
  17.         _target[actionStr] = endNum;//并且把参数强制性变成最终值  
  18.       }  
  19.     }  
  20.       
  21.     //反过来播放一次  
  22.     public function back(){  
  23.       stop();  
  24.       num2 = 0;  
  25.       _target[actionStr] = endNum;  
  26.       _target.addEventListener(Event.ENTER_FRAME,fun2);  
  27.     }  
  28.       
  29.     //反过来播放的执行事件  
  30.     private function fun2(e:Event){  
  31.       var t = num2 ++;  
  32.       var d = proNum;  
  33.       var b = endNum;  
  34.       var c = startNum - endNum;  
  35.       _target[actionStr] = func(t,b,c,d);  
  36.       if(t > d){  
  37.         stop();  
  38.         _target[actionStr] = startNum;  
  39.       }  
  40.     }  
  41.       
  42.     //停止播放  
  43.     public function stop(){  
  44.       _target.removeEventListener(Event.ENTER_FRAME,fun1);  
  45.       _target.removeEventListener(Event.ENTER_FRAME,fun2);  
  46.       dispatchEvent(new Event("stop"));  
  47.     }  
  48.   }  

 


    xiangpei001  版权所有
    禁止任何用途(禁止转载、商用和个人使用)


所属分类:技术经验分享

本文标签:As3.0 Tween flash缓冲效果

各位正在潜水的同学请注意,有0位无聊人士 在EBIBI附近出没!







    点击我更换图片 看不清
    评论内容 (*必填):

    (Ctrl + Enter 快速提交)