All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scaffold.libs_as.starling.animation.Tween.as Maven / Gradle / Ivy

// =================================================================================================
//
//	Starling Framework
//	Copyright 2011-2015 Gamua. All Rights Reserved.
//
//	This program is free software. You can redistribute and/or modify it
//	in accordance with the terms of the accompanying license agreement.
//
// =================================================================================================


package starling.animation
{
    import starling.core.starling_internal;
    import starling.events.Event;
    import starling.events.EventDispatcher;

    /** A Tween animates numeric properties of objects. It uses different transition functions
     *  to give the animations various styles.
     *  
     *  

The primary use of this class is to do standard animations like movement, fading, * rotation, etc. But there are no limits on what to animate; as long as the property you want * to animate is numeric (int, uint, Number), the tween can handle it. For a list * of available Transition types, look at the "Transitions" class.

* *

Here is an example of a tween that moves an object to the right, rotates it, and * fades it out:

* * * var tween:Tween = new Tween(object, 2.0, Transitions.EASE_IN_OUT); * tween.animate("x", object.x + 50); * tween.animate("rotation", deg2rad(45)); * tween.fadeTo(0); // equivalent to 'animate("alpha", 0)' * Starling.juggler.add(tween); * *

Note that the object is added to a juggler at the end of this sample. That's because a * tween will only be executed if its "advanceTime" method is executed regularly - the * juggler will do that for you, and will remove the tween when it is finished.

* * @see Juggler * @see Transitions */ public class Tween extends EventDispatcher implements IAnimatable { private static const HINT_MARKER:String = '#'; private var _target:Object; private var _transitionFunc:Function; private var _transitionName:String; private var _properties:Vector.; private var _startValues:Vector.; private var _endValues:Vector.; private var _updateFuncs:Vector.; private var _onStart:Function; private var _onUpdate:Function; private var _onRepeat:Function; private var _onComplete:Function; private var _onStartArgs:Array; private var _onUpdateArgs:Array; private var _onRepeatArgs:Array; private var _onCompleteArgs:Array; private var _totalTime:Number; private var _currentTime:Number; private var _progress:Number; private var _delay:Number; private var _roundToInt:Boolean; private var _nextTween:Tween; private var _repeatCount:int; private var _repeatDelay:Number; private var _reverse:Boolean; private var _currentCycle:int; /** Creates a tween with a target, duration (in seconds) and a transition function. * @param target the object that you want to animate * @param time the duration of the Tween (in seconds) * @param transition can be either a String (e.g. one of the constants defined in the * Transitions class) or a function. Look up the 'Transitions' class for a * documentation about the required function signature. */ public function Tween(target:Object, time:Number, transition:Object="linear") { reset(target, time, transition); } /** Resets the tween to its default values. Useful for pooling tweens. */ public function reset(target:Object, time:Number, transition:Object="linear"):Tween { _target = target; _currentTime = 0.0; _totalTime = Math.max(0.0001, time); _progress = 0.0; _delay = _repeatDelay = 0.0; _onStart = _onUpdate = _onRepeat = _onComplete = null; _onStartArgs = _onUpdateArgs = _onRepeatArgs = _onCompleteArgs = null; _roundToInt = _reverse = false; _repeatCount = 1; _currentCycle = -1; _nextTween = null; if (transition is String) this.transition = transition as String; else if (transition is Function) this.transitionFunc = transition as Function; else throw new ArgumentError("Transition must be either a string or a function"); if (_properties) _properties.length = 0; else _properties = new []; if (_startValues) _startValues.length = 0; else _startValues = new []; if (_endValues) _endValues.length = 0; else _endValues = new []; if (_updateFuncs) _updateFuncs.length = 0; else _updateFuncs = new []; return this; } /** Animates the property of the target to a certain value. You can call this method * multiple times on one tween. * *

Some property types are handled in a special way:

*
    *
  • If the property contains the string color or Color, * it will be treated as an unsigned integer with a color value * (e.g. 0xff0000 for red). Each color channel will be animated * individually.
  • *
  • The same happens if you append the string #rgb to the name.
  • *
  • If you append #rad, the property is treated as an angle in radians, * making sure it always uses the shortest possible arc for the rotation.
  • *
  • The string #deg does the same for angles in degrees.
  • *
*/ public function animate(property:String, endValue:Number):void { if (_target == null) return; // tweening null just does nothing. var pos:int = _properties.length; var updateFunc:Function = getUpdateFuncFromProperty(property); _properties[pos] = getPropertyName(property); _startValues[pos] = Number.NaN; _endValues[pos] = endValue; _updateFuncs[pos] = updateFunc; } /** Animates the 'scaleX' and 'scaleY' properties of an object simultaneously. */ public function scaleTo(factor:Number):void { animate("scaleX", factor); animate("scaleY", factor); } /** Animates the 'x' and 'y' properties of an object simultaneously. */ public function moveTo(x:Number, y:Number):void { animate("x", x); animate("y", y); } /** Animates the 'alpha' property of an object to a certain target value. */ public function fadeTo(alpha:Number):void { animate("alpha", alpha); } /** Animates the 'rotation' property of an object to a certain target value, using the * smallest possible arc. 'type' may be either 'rad' or 'deg', depending on the unit of * measurement. */ public function rotateTo(angle:Number, type:String="rad"):void { animate("rotation#" + type, angle); } /** @inheritDoc */ public function advanceTime(time:Number):void { if (time == 0 || (_repeatCount == 1 && _currentTime == _totalTime)) return; var i:int; var previousTime:Number = _currentTime; var restTime:Number = _totalTime - _currentTime; var carryOverTime:Number = time > restTime ? time - restTime : 0.0; _currentTime += time; if (_currentTime <= 0) return; // the delay is not over yet else if (_currentTime > _totalTime) _currentTime = _totalTime; if (_currentCycle < 0 && previousTime <= 0 && _currentTime > 0) { _currentCycle++; if (_onStart != null) _onStart.apply(this, _onStartArgs); } var ratio:Number = _currentTime / _totalTime; var reversed:Boolean = _reverse && (_currentCycle % 2 == 1); var numProperties:int = _startValues.length; _progress = reversed ? _transitionFunc(1.0 - ratio) : _transitionFunc(ratio); for (i=0; i= _totalTime) { if (_repeatCount == 0 || _repeatCount > 1) { _currentTime = -_repeatDelay; _currentCycle++; if (_repeatCount > 1) _repeatCount--; if (_onRepeat != null) _onRepeat.apply(this, _onRepeatArgs); } else { // save callback & args: they might be changed through an event listener var onComplete:Function = _onComplete; var onCompleteArgs:Array = _onCompleteArgs; // in the 'onComplete' callback, people might want to call "tween.reset" and // add it to another juggler; so this event has to be dispatched *before* // executing 'onComplete'. dispatchEventWith(Event.REMOVE_FROM_JUGGLER); if (onComplete != null) onComplete.apply(this, onCompleteArgs); } } if (carryOverTime) advanceTime(carryOverTime); } // animation hints private function getUpdateFuncFromProperty(property:String):Function { var updateFunc:Function; var hint:String = getPropertyHint(property); switch (hint) { case null: updateFunc = updateStandard; break; case "rgb": updateFunc = updateRgb; break; case "rad": updateFunc = updateRad; break; case "deg": updateFunc = updateDeg; break; default: trace("[Starling] Ignoring unknown property hint:", hint); updateFunc = updateStandard; } return updateFunc; } /** @private */ internal static function getPropertyHint(property:String):String { // colorization is special; it does not require a hint marker, just the word 'color'. if (property.indexOf("color") != -1 || property.indexOf("Color") != -1) return "rgb"; var hintMarkerIndex:int = property.indexOf(HINT_MARKER); if (hintMarkerIndex != -1) return property.substr(hintMarkerIndex+1); else return null; } /** @private */ internal static function getPropertyName(property:String):String { var hintMarkerIndex:int = property.indexOf(HINT_MARKER); if (hintMarkerIndex != -1) return property.substring(0, hintMarkerIndex); else return property; } private function updateStandard(property:String, startValue:Number, endValue:Number):void { var newValue:Number = startValue + _progress * (endValue - startValue); if (_roundToInt) newValue = Math.round(newValue); _target[property] = newValue; } private function updateRgb(property:String, startValue:Number, endValue:Number):void { var startColor:uint = uint(startValue); var endColor:uint = uint(endValue); var startA:uint = (startColor >> 24) & 0xff; var startR:uint = (startColor >> 16) & 0xff; var startG:uint = (startColor >> 8) & 0xff; var startB:uint = (startColor ) & 0xff; var endA:uint = (endColor >> 24) & 0xff; var endR:uint = (endColor >> 16) & 0xff; var endG:uint = (endColor >> 8) & 0xff; var endB:uint = (endColor ) & 0xff; var newA:uint = startA + (endA - startA) * _progress; var newR:uint = startR + (endR - startR) * _progress; var newG:uint = startG + (endG - startG) * _progress; var newB:uint = startB + (endB - startB) * _progress; _target[property] = (newA << 24) | (newR << 16) | (newG << 8) | newB; } private function updateRad(property:String, startValue:Number, endValue:Number):void { updateAngle(Math.PI, property, startValue, endValue); } private function updateDeg(property:String, startValue:Number, endValue:Number):void { updateAngle(180, property, startValue, endValue); } private function updateAngle(pi:Number, property:String, startValue:Number, endValue:Number):void { while (Math.abs(endValue - startValue) > pi) { if (startValue < endValue) endValue -= 2.0 * pi; else endValue += 2.0 * pi; } updateStandard(property, startValue, endValue); } /** The end value a certain property is animated to. Throws an ArgumentError if the * property is not being animated. */ public function getEndValue(property:String):Number { var index:int = _properties.indexOf(property); if (index == -1) throw new ArgumentError("The property '" + property + "' is not animated"); else return _endValues[index] as Number; } /** Indicates if the tween is finished. */ public function get isComplete():Boolean { return _currentTime >= _totalTime && _repeatCount == 1; } /** The target object that is animated. */ public function get target():Object { return _target; } /** The transition method used for the animation. @see Transitions */ public function get transition():String { return _transitionName; } public function set transition(value:String):void { _transitionName = value; _transitionFunc = Transitions.getTransition(value); if (_transitionFunc == null) throw new ArgumentError("Invalid transiton: " + value); } /** The actual transition function used for the animation. */ public function get transitionFunc():Function { return _transitionFunc; } public function set transitionFunc(value:Function):void { _transitionName = "custom"; _transitionFunc = value; } /** The total time the tween will take per repetition (in seconds). */ public function get totalTime():Number { return _totalTime; } /** The time that has passed since the tween was created (in seconds). */ public function get currentTime():Number { return _currentTime; } /** The current progress between 0 and 1, as calculated by the transition function. */ public function get progress():Number { return _progress; } /** The delay before the tween is started (in seconds). @default 0 */ public function get delay():Number { return _delay; } public function set delay(value:Number):void { _currentTime = _currentTime + _delay - value; _delay = value; } /** The number of times the tween will be executed. * Set to '0' to tween indefinitely. @default 1 */ public function get repeatCount():int { return _repeatCount; } public function set repeatCount(value:int):void { _repeatCount = value; } /** The amount of time to wait between repeat cycles (in seconds). @default 0 */ public function get repeatDelay():Number { return _repeatDelay; } public function set repeatDelay(value:Number):void { _repeatDelay = value; } /** Indicates if the tween should be reversed when it is repeating. If enabled, * every second repetition will be reversed. @default false */ public function get reverse():Boolean { return _reverse; } public function set reverse(value:Boolean):void { _reverse = value; } /** Indicates if the numeric values should be cast to Integers. @default false */ public function get roundToInt():Boolean { return _roundToInt; } public function set roundToInt(value:Boolean):void { _roundToInt = value; } /** A function that will be called when the tween starts (after a possible delay). */ public function get onStart():Function { return _onStart; } public function set onStart(value:Function):void { _onStart = value; } /** A function that will be called each time the tween is advanced. */ public function get onUpdate():Function { return _onUpdate; } public function set onUpdate(value:Function):void { _onUpdate = value; } /** A function that will be called each time the tween finishes one repetition * (except the last, which will trigger 'onComplete'). */ public function get onRepeat():Function { return _onRepeat; } public function set onRepeat(value:Function):void { _onRepeat = value; } /** A function that will be called when the tween is complete. */ public function get onComplete():Function { return _onComplete; } public function set onComplete(value:Function):void { _onComplete = value; } /** The arguments that will be passed to the 'onStart' function. */ public function get onStartArgs():Array { return _onStartArgs; } public function set onStartArgs(value:Array):void { _onStartArgs = value; } /** The arguments that will be passed to the 'onUpdate' function. */ public function get onUpdateArgs():Array { return _onUpdateArgs; } public function set onUpdateArgs(value:Array):void { _onUpdateArgs = value; } /** The arguments that will be passed to the 'onRepeat' function. */ public function get onRepeatArgs():Array { return _onRepeatArgs; } public function set onRepeatArgs(value:Array):void { _onRepeatArgs = value; } /** The arguments that will be passed to the 'onComplete' function. */ public function get onCompleteArgs():Array { return _onCompleteArgs; } public function set onCompleteArgs(value:Array):void { _onCompleteArgs = value; } /** Another tween that will be started (i.e. added to the same juggler) as soon as * this tween is completed. */ public function get nextTween():Tween { return _nextTween; } public function set nextTween(value:Tween):void { _nextTween = value; } // tween pooling private static var sTweenPool:Vector. = new []; /** @private */ starling_internal static function fromPool(target:Object, time:Number, transition:Object="linear"):Tween { if (sTweenPool.length) return sTweenPool.pop().reset(target, time, transition); else return new Tween(target, time, transition); } /** @private */ starling_internal static function toPool(tween:Tween):void { // reset any object-references, to make sure we don't prevent any garbage collection tween._onStart = tween._onUpdate = tween._onRepeat = tween._onComplete = null; tween._onStartArgs = tween._onUpdateArgs = tween._onRepeatArgs = tween._onCompleteArgs = null; tween._target = null; tween._transitionFunc = null; tween.removeEventListeners(); sTweenPool.push(tween); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy