Revamping animations to be based off of ENTER_FRAME rather than
using a rapidly-expiring Timer. Cleaned up some other bits. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@211 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -1,101 +1,10 @@
|
||||
package com.threerings.flash {
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
|
||||
import flash.events.TimerEvent;
|
||||
|
||||
import flash.utils.getTimer; // func import
|
||||
import flash.utils.Timer;
|
||||
|
||||
public class Animation
|
||||
public interface Animation
|
||||
{
|
||||
public function Animation ()
|
||||
{
|
||||
}
|
||||
|
||||
public function start () :void
|
||||
{
|
||||
addAnimation(this);
|
||||
}
|
||||
|
||||
public function stop () :void
|
||||
{
|
||||
removeAnimation(this);
|
||||
// didStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* The primary working method for your animation.
|
||||
*/
|
||||
protected function enterFrame () :void
|
||||
{
|
||||
// do your business here
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified anim to the list of active anims.
|
||||
*/
|
||||
protected static function addAnimation (anim :Animation) :void
|
||||
{
|
||||
// add it
|
||||
_anims.push(anim);
|
||||
|
||||
// set up the timer
|
||||
if (!_timer) {
|
||||
_timer = new Timer(10); // 10ms: will be limited by frame rate
|
||||
_timer.addEventListener(TimerEvent.TIMER, frameHandler);
|
||||
}
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified anim.
|
||||
*/
|
||||
protected static function removeAnimation (anim :Animation) :void
|
||||
{
|
||||
var dex :int = _anims.indexOf(anim);
|
||||
if (dex != -1) {
|
||||
_anims.splice(dex, 1);
|
||||
|
||||
} else {
|
||||
Log.getLog(Animation).warning("Removing unknown Animation: " + anim);
|
||||
}
|
||||
|
||||
if (_anims.length == 0) {
|
||||
_timer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle our timer event.
|
||||
*/
|
||||
protected static function frameHandler (event :TimerEvent) :void
|
||||
{
|
||||
_now = getTimer();
|
||||
var an :Animation;
|
||||
for (var ii :int = _anims.length - 1; ii >= 0; ii--) {
|
||||
an = Animation(_anims[ii]);
|
||||
if (isNaN(an._start)) {
|
||||
an._start = _now;
|
||||
// an.didStart();
|
||||
}
|
||||
an.enterFrame();
|
||||
}
|
||||
|
||||
// and instruct the flash player to update the display list (now!)
|
||||
event.updateAfterEvent();
|
||||
}
|
||||
|
||||
/** Our own personal start stamp. */
|
||||
protected var _start :Number = NaN;
|
||||
|
||||
/** The current timestamp, accessable to all animations. */
|
||||
protected static var _now :Number;
|
||||
|
||||
/** All the currently running animations. */
|
||||
protected static var _anims :Array = [];
|
||||
|
||||
/** The timer we use to manage our animations. */
|
||||
protected static var _timer :Timer;
|
||||
function updateAnimation (elapsed :Number) :void;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package com.threerings.flash {
|
||||
|
||||
public class AnimationAdapter extends Animation
|
||||
{
|
||||
/**
|
||||
* @param host the display object we'll be animating.
|
||||
* @param enterFrame called on every frame: function (elapsed :Number) :void
|
||||
*/
|
||||
public function AnimationAdapter (enterFrame :Function)
|
||||
{
|
||||
_enterFrame = enterFrame;
|
||||
}
|
||||
|
||||
override protected function enterFrame () :void
|
||||
{
|
||||
_enterFrame(_now - _start);
|
||||
}
|
||||
|
||||
protected var _enterFrame :Function;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.threerings.flash {
|
||||
|
||||
public class AnimationImpl implements Animation
|
||||
{
|
||||
public function startAnimation () :void
|
||||
{
|
||||
AnimationManager.start(this);
|
||||
}
|
||||
|
||||
public function stopAnimation () :void
|
||||
{
|
||||
AnimationManager.stop(this);
|
||||
}
|
||||
|
||||
public function updateAnimation (elapsed :Number) :void
|
||||
{
|
||||
// please implement!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package com.threerings.flash {
|
||||
|
||||
import flash.display.DisplayObject;
|
||||
import flash.display.Sprite;
|
||||
|
||||
import flash.events.Event;
|
||||
|
||||
import flash.utils.getTimer; // func import
|
||||
|
||||
/**
|
||||
* Manages animations.
|
||||
*/
|
||||
public class AnimationManager
|
||||
{
|
||||
public function AnimationManager ()
|
||||
{
|
||||
throw new Error("Static only");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start (or restart) the specified animation.
|
||||
*/
|
||||
public static function start (anim :Animation) :void
|
||||
{
|
||||
var dex :int = _anims.indexOf(anim);
|
||||
if (dex == -1) {
|
||||
_anims.push(anim);
|
||||
_anims.push(NaN);
|
||||
|
||||
} else {
|
||||
_anims[dex + 1] = NaN; // mark it as starting
|
||||
}
|
||||
|
||||
if (!_framer) {
|
||||
_framer = new Sprite();
|
||||
_framer.addEventListener(Event.ENTER_FRAME, frameHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the specified animation.
|
||||
*/
|
||||
public static function stop (anim :Animation) :void
|
||||
{
|
||||
var dex :int = _anims.indexOf(anim);
|
||||
if (dex == -1) {
|
||||
Log.getLog(AnimationManager).warning("Stopping unknown Animation: " + anim);
|
||||
return;
|
||||
}
|
||||
|
||||
// remove it
|
||||
_anims.splice(dex, 2);
|
||||
|
||||
// See if we should clean up a bit
|
||||
if (_anims.length == 0) {
|
||||
_framer.removeEventListener(Event.ENTER_FRAME, frameHandler);
|
||||
_framer = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Track a DisplayObject that is also an Animation- it will
|
||||
* automatically be started when added to the stage and
|
||||
* stopped when removed.
|
||||
*/
|
||||
public static function addDisplayAnimation (disp :DisplayObject) :void
|
||||
{
|
||||
if (!(disp is Animation)) {
|
||||
throw new ArgumentError("Must be an Animation");
|
||||
}
|
||||
|
||||
disp.addEventListener(Event.ADDED_TO_STAGE, startDisplayAnim);
|
||||
disp.addEventListener(Event.REMOVED_FROM_STAGE, stopDisplayAnim);
|
||||
if (disp.stage != null) {
|
||||
// it's on the stage now!
|
||||
start(Animation(disp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop tracking the specified DisplayObject animation.
|
||||
*/
|
||||
public static function removeDisplayAnimation (disp :DisplayObject) :void
|
||||
{
|
||||
disp.removeEventListener(Event.ADDED_TO_STAGE, startDisplayAnim);
|
||||
disp.removeEventListener(Event.REMOVED_FROM_STAGE, stopDisplayAnim);
|
||||
if (disp.stage != null) {
|
||||
stop(Animation(disp));
|
||||
}
|
||||
}
|
||||
|
||||
protected static function startDisplayAnim (event :Event) :void
|
||||
{
|
||||
start(event.currentTarget as Animation);
|
||||
}
|
||||
|
||||
protected static function stopDisplayAnim (event :Event) :void
|
||||
{
|
||||
stop(event.currentTarget as Animation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ENTER_FRAME event.
|
||||
*/
|
||||
protected static function frameHandler (event :Event) :void
|
||||
{
|
||||
var now :Number = getTimer();
|
||||
var anim :Animation;
|
||||
var startStamp :Number;
|
||||
for (var ii :int = _anims.length - 2; ii >= 0; ii -= 2) {
|
||||
anim = Animation(_anims[ii]);
|
||||
startStamp = Number(_anims[ii + 1]);
|
||||
if (isNaN(startStamp)) {
|
||||
_anims[ii + 1] = startStamp = now;
|
||||
}
|
||||
anim.updateAnimation(now - startStamp);
|
||||
}
|
||||
}
|
||||
|
||||
/** The current timestamp, accessable to all animations. */
|
||||
protected static var _now :Number;
|
||||
|
||||
/** All the currently running animations. */
|
||||
protected static var _anims :Array = [];
|
||||
|
||||
protected static var _framer :Sprite;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import flash.text.TextFieldAutoSize;
|
||||
import flash.text.TextFormat;
|
||||
|
||||
public class FloatingTextAnimation extends TextField
|
||||
implements Animation
|
||||
{
|
||||
public static function create (
|
||||
text :String, duration :Number = 1000, dy :int = -10,
|
||||
@@ -41,10 +42,7 @@ public class FloatingTextAnimation extends TextField
|
||||
|
||||
public function FloatingTextAnimation ()
|
||||
{
|
||||
addEventListener(Event.ADDED_TO_STAGE, handleAdded);
|
||||
addEventListener(Event.REMOVED_FROM_STAGE, handleRemoved);
|
||||
|
||||
_anim = new AnimationAdapter(enterFrame);
|
||||
AnimationManager.addDisplayAnimation(this);
|
||||
}
|
||||
|
||||
override public function set x (val :Number) :void
|
||||
@@ -57,11 +55,12 @@ public class FloatingTextAnimation extends TextField
|
||||
super.y = _startY = (val - height/2);
|
||||
}
|
||||
|
||||
protected function enterFrame (elapsed :Number) :void
|
||||
// from Animation
|
||||
public function updateAnimation (elapsed :Number) :void
|
||||
{
|
||||
var perc :Number = elapsed / duration;
|
||||
if (perc >= 1) {
|
||||
parent.removeChild(this);
|
||||
AnimationManager.removeDisplayAnimation(this);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -69,18 +68,6 @@ public class FloatingTextAnimation extends TextField
|
||||
super.y = _startY + (dy * perc);
|
||||
}
|
||||
|
||||
protected function handleAdded (... ignored) :void
|
||||
{
|
||||
_anim.start();
|
||||
}
|
||||
|
||||
protected function handleRemoved (... ignored) :void
|
||||
{
|
||||
_anim.stop();
|
||||
}
|
||||
|
||||
protected var _startY :Number;
|
||||
|
||||
protected var _anim :AnimationAdapter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import flash.text.TextFormat;
|
||||
import flash.utils.getTimer; // function import
|
||||
|
||||
public class TextCharAnimation extends Sprite
|
||||
implements Animation
|
||||
{
|
||||
public function TextCharAnimation (text :String, fn :Function, format :TextFormat)
|
||||
{
|
||||
@@ -40,8 +41,15 @@ public class TextCharAnimation extends Sprite
|
||||
alignment.y = -(h/2);
|
||||
addChild(alignment);
|
||||
|
||||
addEventListener(Event.ADDED_TO_STAGE, handleAdded);
|
||||
addEventListener(Event.REMOVED_FROM_STAGE, handleRemoved);
|
||||
AnimationManager.addDisplayAnimation(this);
|
||||
}
|
||||
|
||||
// from Animation
|
||||
public function updateAnimation (elapsed :Number) :void
|
||||
{
|
||||
for (var ii :int = 0; ii < _texts.length; ii++) {
|
||||
_texts[ii].y = _fn(elapsed, ii);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createTextField (format :TextFormat) :TextField
|
||||
@@ -51,27 +59,6 @@ public class TextCharAnimation extends Sprite
|
||||
return tf;
|
||||
}
|
||||
|
||||
protected function handleAdded (... ignored) :void
|
||||
{
|
||||
// TODO: use animation stuff instead?
|
||||
addEventListener(Event.ENTER_FRAME, handleFrame);
|
||||
_startStamp = getTimer();
|
||||
handleFrame(); // update immediately...
|
||||
}
|
||||
|
||||
protected function handleRemoved (... ignored) :void
|
||||
{
|
||||
removeEventListener(Event.ENTER_FRAME, handleFrame);
|
||||
}
|
||||
|
||||
protected function handleFrame (... ignored) :void
|
||||
{
|
||||
var elapsed :Number = getTimer() - _startStamp;
|
||||
for (var ii :int = 0; ii < _texts.length; ii++) {
|
||||
_texts[ii].y = _fn(elapsed, ii);
|
||||
}
|
||||
}
|
||||
|
||||
protected var _startStamp :Number;
|
||||
|
||||
protected var _texts :Array = [];
|
||||
|
||||
Reference in New Issue
Block a user