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:
Ray Greenwell
2007-04-26 23:52:25 +00:00
parent 79c388a906
commit 5f83a3bbcf
6 changed files with 165 additions and 155 deletions
+2 -93
View File
@@ -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 = [];