From 5f83a3bbcfbe1e99d336e7f5f922e379af2b2d1a Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Thu, 26 Apr 2007 23:52:25 +0000 Subject: [PATCH] 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 --- src/as/com/threerings/flash/Animation.as | 95 +------------ .../com/threerings/flash/AnimationAdapter.as | 21 --- src/as/com/threerings/flash/AnimationImpl.as | 20 +++ .../com/threerings/flash/AnimationManager.as | 128 ++++++++++++++++++ .../threerings/flash/FloatingTextAnimation.as | 23 +--- .../com/threerings/flash/TextCharAnimation.as | 33 ++--- 6 files changed, 165 insertions(+), 155 deletions(-) delete mode 100644 src/as/com/threerings/flash/AnimationAdapter.as create mode 100644 src/as/com/threerings/flash/AnimationImpl.as create mode 100644 src/as/com/threerings/flash/AnimationManager.as diff --git a/src/as/com/threerings/flash/Animation.as b/src/as/com/threerings/flash/Animation.as index b31260c8..0a269c53 100644 --- a/src/as/com/threerings/flash/Animation.as +++ b/src/as/com/threerings/flash/Animation.as @@ -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; } } diff --git a/src/as/com/threerings/flash/AnimationAdapter.as b/src/as/com/threerings/flash/AnimationAdapter.as deleted file mode 100644 index 1463d5e8..00000000 --- a/src/as/com/threerings/flash/AnimationAdapter.as +++ /dev/null @@ -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; -} -} diff --git a/src/as/com/threerings/flash/AnimationImpl.as b/src/as/com/threerings/flash/AnimationImpl.as new file mode 100644 index 00000000..2f3cf4cc --- /dev/null +++ b/src/as/com/threerings/flash/AnimationImpl.as @@ -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! + } +} +} diff --git a/src/as/com/threerings/flash/AnimationManager.as b/src/as/com/threerings/flash/AnimationManager.as new file mode 100644 index 00000000..576ab3d2 --- /dev/null +++ b/src/as/com/threerings/flash/AnimationManager.as @@ -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; +} +} diff --git a/src/as/com/threerings/flash/FloatingTextAnimation.as b/src/as/com/threerings/flash/FloatingTextAnimation.as index a7f23230..e15d388d 100644 --- a/src/as/com/threerings/flash/FloatingTextAnimation.as +++ b/src/as/com/threerings/flash/FloatingTextAnimation.as @@ -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; } } diff --git a/src/as/com/threerings/flash/TextCharAnimation.as b/src/as/com/threerings/flash/TextCharAnimation.as index af7df6c3..5512d7a8 100644 --- a/src/as/com/threerings/flash/TextCharAnimation.as +++ b/src/as/com/threerings/flash/TextCharAnimation.as @@ -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 = [];