Tween类,flash缓冲效果讲解(as3.0)

最近做的东西,对于效果编程比较多,特别是缓冲,加速度等效果,特意研究了一下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帧?
带着这个问题,现在开始看这个类吧!从构造函数看

package fl.transitions
{
import flash.events.*;
import flash.display.*;
import flash.utils.*;
[Event(name="motionChange", type="fl.transitions.TweenEvent")]
[Event(name="motionFinish", type="fl.transitions.TweenEvent")]
[Event(name="motionLoop", type="fl.transitions.TweenEvent")]
[Event(name="motionResume", type="fl.transitions.TweenEvent")]
[Event(name="motionStart", type="fl.transitions.TweenEvent")]
[Event(name="motionStop", type="fl.transitions.TweenEvent")]
public class Tween extends EventDispatcher
{
   protected static var _mc:MovieClip = new MovieClip();

  public var isPlaying:Boolean = false;

   public var obj:Object = null;

  public var prop:String = "";

  public var func:Function = function (t:Number, b:Number, c:Number, d:Number):Number { return c*t/d + b; }

  public var begin:Number = NaN;

  public var change:Number = NaN;

  public var useSeconds:Boolean = false;

  public var prevTime:Number = NaN;

  public var prevPos:Number = NaN;

  public var looping:Boolean = false;

  private var _duration:Number = NaN;

  private var _time:Number = NaN;

  private var _fps:Number = NaN;

  private var _position:Number = NaN;

  private var _startTime:Number = NaN;

  private var _intervalID:uint = 0;

  private var _finish:Number = NaN;

  private var _timer:Timer = null;

 public function get time():Number 
 {
 return this._time;
 }

  public function set time(t:Number):void 
  {
    this.prevTime = this._time;
    if (t > this.duration) {
      if (this.looping) {
        this.rewind (t - this._duration);
        this.update();
        this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_LOOP, this._time, this._position));
      } else {
        if (this.useSeconds) {
          this._time = this._duration;
          this.update();
        }
        this.stop();
        this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_FINISH, this._time, this._position));
      }
    } else if (t < 0) {
      this.rewind();
      this.update();
    } else {
      this._time = t;
      this.update();
    }
  }

 public function get duration():Number 
 {
 return this._duration;
 }
 
  public function set duration(d:Number):void 
  {
    this._duration = (d <= 0) ? Infinity : d;
  }

 public function get FPS():Number 
 {
 return this._fps;
 }
 
  public function set FPS(fps:Number):void 
  {
    var oldIsPlaying:Boolean = this.isPlaying;
    this.stopEnterFrame();
    this._fps = fps;
    if (oldIsPlaying) 
    {
      this.startEnterFrame();
    }
  }

 public function get position():Number 
 {
 return this.getPosition(this._time);
 }
 
  public function set position(p:Number):void 
  {
    this.setPosition (p);
  }
 
 public function getPosition(t:Number=NaN):Number 
 {
 if (isNaN(t)) t = this._time;
 return this.func (t, this.begin, this.change, this._duration);
 }

  public function setPosition(p:Number):void 
  {
    this.prevPos = this._position;
    if (this.prop.length)
      this.obj[this.prop] = this._position = p;
    this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_CHANGE, this._time, this._position));  
  }

 public function get finish():Number 
 {
 return this.begin + this.change;
 }
 
  public function set finish(value:Number):void 
  {
    this.change = value - this.begin;
  }
  
  function Tween(obj:Object, prop:String, func:Function, begin:Number, finish:Number, duration:Number, useSeconds:Boolean=false) 
  {
    if (!arguments.length) return;
    this.obj = obj;
    this.prop = prop;
    this.begin = begin;
    this.position = begin;
    this.duration = duration;
    this.useSeconds = useSeconds;
    if (func is Function) this.func = func;
    this.finish = finish;
    this._timer = new Timer(100);
    this.start();
  }

  public function continueTo(finish:Number, duration:Number):void {
    this.begin = this.position;
    this.finish = finish;
    if (!isNaN(duration))
      this.duration = duration;
    this.start();
  }
  
  public function yoyo():void 
  {
    this.continueTo(this.begin, this.time);
  }

  protected function startEnterFrame():void 
  {
    if (isNaN(this._fps)) 
    {
      _mc.addEventListener(Event.ENTER_FRAME, this.onEnterFrame, false, 0, true);
    } 
    else 
    {
      var milliseconds:Number = 1000 / this._fps;
      this._timer.delay = milliseconds;
 this._timer.addEventListener(TimerEvent.TIMER, this.timerHandler, false, 0, true);
 this._timer.start();
    }
    this.isPlaying = true;
  }

  protected function stopEnterFrame():void 
  {
    if (isNaN(this._fps)) 
    {
      _mc.removeEventListener(Event.ENTER_FRAME, this.onEnterFrame);
    } 
    else 
    {
      this._timer.stop();
    }
    this.isPlaying = false;
  }
 
  public function start():void 
  {
    this.rewind();
    this.startEnterFrame();
    this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_START, this._time, this._position));
  }
 
  public function stop():void 
  {
    this.stopEnterFrame();
    this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_STOP, this._time, this._position));
  }

  public function resume():void 
  {
    this.fixTime();
    this.startEnterFrame();
    this.dispatchEvent(new TweenEvent(TweenEvent.MOTION_RESUME, this._time, this._position));
  }
 
  public function rewind(t:Number=0):void 
  {
    this._time = t;
    this.fixTime();
    this.update(); 
  }
 
  public function fforward():void 
  {
    this.time = this._duration;
    this.fixTime();
  }
 
  public function nextFrame():void 
  {
    if (this.useSeconds) 
      this.time = (getTimer() - this._startTime) / 1000;
    else 
      this.time = this._time + 1;
  }

  protected function onEnterFrame(event:Event):void 
  {
    this.nextFrame();
  }

  protected function timerHandler(timerEvent:TimerEvent):void 
  {
    this.nextFrame();
    timerEvent.updateAfterEvent();
  }

  public function prevFrame():void 
  {
    if (!this.useSeconds) this.time = this._time - 1;
  }
  
  private function fixTime():void 
  {
    if (this.useSeconds) 
      this._startTime = getTimer() - this._time*1000;
  }

  private function update():void 
  {
    this.setPosition(this.getPosition(this._time));
  }
  
}
}

不知大家看的如何,反正我现在来告诉你结果,你会发现,实际这个类很简单,他就做了一件事,就是每个时间变化每个不同的状态,而具体怎么变的,谁看到了?比如加速度,弹簧效果等都应该有算法,但是这里面并没有看到算法啊,只看到他每次更改时间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类,源代码:
package fl.transitions.easing
{

public class Regular
{

  public static function easeIn(t:Number, b:Number,
                 c:Number, d:Number):Number
  {
    return c * (t /= d) * t + b;
  }

  public static function easeOut(t:Number, b:Number,
                 c:Number, d:Number):Number
  {
    return -c * (t /= d) * (t - 2) + b;
  }

  public static function easeInOut(t:Number, b:Number,
                   c:Number, d:Number):Number
  {
    if ((t /= d / 2) < 1)
      return c / 2 * t * t + b;

    return -c / 2 * ((--t) * (t - 2) - 1) + b;
  }
}

}

接下来看看,我为了某个项目,赶时间写出来针对显示对象一个非常简单的缓冲类,然后调用了官方的fl.transitions.easing包中的算法
package index.item.pairBumping{
  
  import flash.display.DisplayObject;
  import flash.events.Event;
  import flash.events.EventDispatcher;
  
  public class Motion extends EventDispatcher{
    
    private var _target:DisplayObject;
    private var proNum:Number;
    private var startNum:Number;
    private var endNum:Number;
    private var actionStr:String;
    private var num1:uint;
    private var num2:uint;
    private var func:Function;
    
    //构造函数与Tween基本上一样,只不过没有按时间计算,只有按帧运动
    //每个参数所表示的值也是一样的,fun:Function传入的参数和Tween一样,使用官方的fl.transitions.easing包
    public function Motion(target:DisplayObject,str:*,fun:Function,_start:Number = 0,_end:Number = 1,_pro:Number = 4){
      actionStr = str;
      _target = target;
      proNum = _pro;
      startNum = _start;
      endNum = _end;
      func = fun;
    }
    
    //创建Motion实例化后,并没有立即播放得执行play才播放,当然播放完一次,也能使用play继续播放
    public function play(){
      stop();
      num1 = 0;
      _target[actionStr] = startNum;
      _target.addEventListener(Event.ENTER_FRAME,fun1);
    }
    
    //顺走所执行事件
    private function fun1(e:Event){
      var t = num1 ++;//当前运行时间
      var d = proNum;//总时间
      var b = startNum;//开始值
      var c = endNum - startNum;//要改变的值
      _target[actionStr] = func(t,b,c,d);//调用官方算法,并且传入4个参数,进行计算!
      if(t > d){//判断是否时间到了
        stop();//ok,播放完毕,那么我们停止吧
        _target[actionStr] = endNum;//并且把参数强制性变成最终值
      }
    }
    
    //反过来播放一次
    public function back(){
      stop();
      num2 = 0;
      _target[actionStr] = endNum;
      _target.addEventListener(Event.ENTER_FRAME,fun2);
    }
    
    //反过来播放的执行事件
    private function fun2(e:Event){
      var t = num2 ++;
      var d = proNum;
      var b = endNum;
      var c = startNum - endNum;
      _target[actionStr] = func(t,b,c,d);
      if(t > d){
        stop();
        _target[actionStr] = startNum;
      }
    }
    
    //停止播放
    public function stop(){
      _target.removeEventListener(Event.ENTER_FRAME,fun1);
      _target.removeEventListener(Event.ENTER_FRAME,fun2);
      dispatchEvent(new Event("stop"));
    }
  }
}

你可能感兴趣的:(C++,c,算法,C#,Flash)