最近做的东西,对于效果编程比较多,特别是缓冲,加速度等效果,特意研究了一下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"));
}
}
}