as3.0中的Tween类,flash缓冲效果讲解
最近做的东西,对于效果编程比较多,特别是缓冲,加速度等效果,特意研究了一下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
- {
- thisthis.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) {
- thisthis._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 {
- tthis._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
- {
- thisthis.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 {
- thisthis.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
- {
- tthis._time = t;
- this.fixTime();
- this.update();
- }
- public function fforward():void
- {
- thisthis.time = this._duration;
- this.fixTime();
- }
- public function nextFrame():void
- {
- if (this.useSeconds)
- this.time = (getTimer() - this._startTime) / 1000;
- else
- thisthis.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) thisthis.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;
- funfunc = 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"));
- }
- }
- }




