r3dux.org

A number-pimping side project from the valleys in *NEW* upside-down flavour.

  • Home
  • ABOUT
  • OLD SITE
  • SEARCH
  • FEEDBACK

ActionScript 3.0: A Dynamic Frame Rate Switching Class to Lower CPU Usage

r3dux | January 20, 2010

Flash gets a lot of negative press because it’s seen as using a heap of CPU time and bogging everything down. And it’s a fair cop. Most flash will eat up your CPU cycles even when it’s sitting there doing nothing. But this isn’t a fault of flash, but rather of flash developers. Let me explain…

When you start a piece of flash work, you assign it a frame rate at which you want it to run, so it’ll update the screen, say, 30 times a second. This is all fine and good for when you’re animating things on the stage. But what about when you’re not? Well, it’s still running at 30 frames per second and chewing up your CPU like a crazy melon farmer. This is Not A Good Thing. So, anyhow, I’m watching this video about SWF Framerate Optimisation, and the guy’s showing how you can modify your code to lower the frame rate when there’s not a lot happening, and bring it back up when you’re animating. So I had a crack at it, and lo & behold, it works fine for the specific piece of flash I’d coded it into, so I wondered if I couldn’t just go and make a RateController class. This way, I could add a RateController object to any project to dynamically change the project’s frame rate depending on whether the mouse was over the stage or not.

And after much swearing about not having global access to the stage properties, I found that I COULD!!!

Here’s a working example placed into the attracting particles code I wrote yesterday:

Note: The animation starts at full speed for two seconds on startup. It’ll drop to the sleeping rate (5 fps) two seconds after the mouse leaves the stage, and then ramps back up to its waking rate (30 fps) instantly when the cursor is back over the stage. The FPSCounter shows intermediate numbers because it’s based on an average.

To add a RateController to any flash project, you can just use something like:

import RateController;
 
// Add a new RateController, uses the root stage, runs at 5fps when sleeping, 30fps 
// when active (i.e. when mouse is over the stage), and uses a 2000 millisecond
// delay after the mouse leaves the stage before dropping the FPS to the sleeping rate.
addChild(new RateController(stage, 5, 30, 2000));

Not bad, eh?

Full class code & file downloads after the jump…

Behold the RateController Class in all its over-commented glory!:

package
{
	import flash.display.Stage;
	import flash.display.MovieClip;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.events.MouseEvent;
	import flash.events.Event;
 
	public class RateController extends MovieClip
	{
		static var switchStateTimer:Timer; // Timer used for when to actually switch states after mouse has left stage
		static var firstRunTimer:Timer; // Timer used to allow full framerate briefly on startup
 
		static var active:Boolean = true;         // Whether the animation is active
		static var instantChange:Boolean = true;  // Whether we're going to instantly change the frame rate
		static var firstRun:Boolean = true;       // Animate normally for duration of timer at startup
 
		var sleepFrameRate:uint;     // The frame rate for when the mouse is not on the stage
		var activeFrameRate:uint;    // The frame rate for when the mouse IS on the stage
		var switchStateDelay:Number; // How long to animate at full rate after the mouse cursor has left the stage
		var currentStage:Stage;	 // A Stage that points to our root stage, we need this to set the framerate
 
		// Constructor
		public function RateController(theStage:Stage, theSleepFrameRate:uint, theActiveFrameRate:uint, theSwitchStateDelay:Number)
		{
			this.currentStage = theStage;
 
			this.sleepFrameRate = theSleepFrameRate;
			this.activeFrameRate = theActiveFrameRate;
			this.switchStateDelay = theSwitchStateDelay;
 
			// Create (but not start!) our timer to switch sleep/wake after a given delay
			switchStateTimer = new Timer(this.switchStateDelay);
 
			// This sleep listener will always listen for the mouse leaving the stage
			this.currentStage.addEventListener(Event.MOUSE_LEAVE, switchController); 
 
			trace("Our current stage is: " + this.currentStage);
 
			// When we start, we want to run at full speed for a little bit to allow any
			// initial animation to happen at the correct rate, and then after a small while
			// put the animation to sleep (if the mouse is moving over it it'll instantly wake
			// up anyway)
			if (firstRun == true) {
				firstRunTimer = new Timer(this.switchStateDelay);
				firstRunTimer.addEventListener(TimerEvent.TIMER, switchStates);
				firstRunTimer.start();
			}
 
		} // End of constructor
 
		// Function to control the frame rate switching
		private function switchController(e:Event):void
		{
			trace("At switchController function...");
			trace("Frame rate is currently: " + stage.frameRate + "\n");
 
			// If we're going to sleep, set the sleep frame rate AFTER the timer delay
			if (instantChange == false) {
 
				trace("Sleeping after timer expires.");
 
				// If we're going to sleep, switch states after the timer delay
				switchStateTimer.addEventListener(TimerEvent.TIMER, switchStates);
				switchStateTimer.start();
			}
			else // If we're waking up, we want to set our active frame rate instantly!
			{
				trace("Waking immediately.");
 
				// switchStates expects a timer event, so we have to pass it a bogus one.
				// Bit of a bodge, I know =/
				var foo:TimerEvent;
				switchStates(foo);
			}
 
		} // End of switchController function
 
		// Function to actually switch the states
		private function switchStates(e:TimerEvent):void
		{
			// If we haven't been called from our initial startup timer
			if (firstRun == false) {
 
				trace("At switchStates function. Stopping timer and switching states...");
				trace("active currently has the value: " + active + "\n");
				switchStateTimer.stop();
				switchStateTimer.removeEventListener(TimerEvent.TIMER, switchStates);
 
				// Swap sleep to wake or vice versa
				if (active == false) // If the animation's asleep, wake it up!
				{
					// Set our flags
					active = true;
					instantChange = false;
 
					// Put the animation to it's waking frame rate and remove the listener for mouse activity on the stage
					this.currentStage.removeEventListener(MouseEvent.MOUSE_MOVE, switchController);
					this.currentStage.frameRate = activeFrameRate;
 
					trace("Setting flash to wake state, where active has the value: " + active);
					trace("Setting wake frame rate: " + stage.frameRate + "\n");
				}
				else // If the animation's awake, put it to sleep!
				{
					trace("active must be true and we're switching states...");
 
					// Set our flags so we know we're not active, and we want to instantly jump
					// to our active framerate when the mouse returns to the stage
					active = false;
					instantChange = true;
 
					// Put the animation to it's sleeping frame rate and add a listener for mouse activity on the stage
					this.currentStage.frameRate = sleepFrameRate;
					this.currentStage.addEventListener(MouseEvent.MOUSE_MOVE, switchController);
 
					trace("Timer has expired, so setting flash to sleep state.");
					trace("Setting sleep frame rate: " + stage.frameRate + "\n");
				}
			}
			else // If we HAVE been called on initial startup (firstRun == true)
			{
				trace("Putting to sleep after initial firstRun timer\n");
 
				// Flip the flags so that:
				firstRun = false;	// We will no longer be in firstRun mode		
				active = false;		// Assume mouse not initially over stage, so the animation is in sleep mode
				instantChange = true;	// When we activate, we want the full frame rate instantly
 
				// Put the animation to it's sleeping frame rate and add a listener for mouse activity on the stage
				this.currentStage.frameRate = sleepFrameRate;
				this.currentStage.addEventListener(MouseEvent.MOUSE_MOVE, switchController);
 
				// Remove our firstRun timer
				firstRunTimer.stop();
				firstRunTimer.removeEventListener(TimerEvent.TIMER, switchStates);
			}
 
		} // End of switch states function
 
	} // End of RateController class
 
} // End of package

There’s a lot of debug code in there at the moment so you can see what it’s doing while it’s doing it, but the version you can download below has all that stripped out.

RateController Class source file: RateController.as

Now for a beer, debugging that thing’s given me a headache…

Related posts:

  1. ActionScript 3.0 Particle Systems #5: Smoke Effect
  2. ActionScript 3.0 Particle Systems #6: Particle Attraction
  3. ActionScript 3.0 Particle Systems #2: Snow Effect
  4. ActionScript 3.0 Particle Systems #1: Random Motion
  5. ActionScript 3.0 Particle Systems #4: Bubbles
Categories
Coding
Tags
ActionScript, ActionScript 3.0, Adobe, Class, CPU, CS4, Dynamic, Flash, Frame, Framerate, Rate
Comments rss
Comments rss
Trackback
Trackback
Print This Post Print This Post

« ActionScript 3.0 Particle Systems #6: Particle Attraction Edward Sharpe and the Magnetic Zeros – Home »

3 Responses to “ActionScript 3.0: A Dynamic Frame Rate Switching Class to Lower CPU Usage”

  1. ActionScript 3.0 Particle Systems #5: Smoke Effect | r3dux.org says:
    January 21, 2010 at 11:46 am

    [...] I’ve modified the above example (but not the associated source code and files) to use the RateController Class I wrote yesterday. Aside from adding a RateController object, the only other modification was [...]

    Reply
  2. Brandon says:
    January 22, 2011 at 3:59 am

    I frikkin love this dude! Thank you so much for putting it together and making it so simple to implement. Much cudos!

    Reply
    • r3dux says:
      January 22, 2011 at 8:30 am

      No worries – glad you found it useful =D

      Reply

Leave a Reply

Click here to cancel reply.

Translate

Categories

Archives

Tags

3D ActionScript ActionScript 3.0 Adobe AI Ballarat Bash C++ Class Convert CS4 Effect Film Flash GLSL Gnome Hack How-To install Jaunty Java Kinect Linkage Linux Mash-Up Microsoft Motion OpenGL Particle Photoshop Problem PS3 Remix Remove Retro script Slides Sound Systems Ubuntu Video VirtualBox Wii Windows XBox

Gamercard

OpenR3dux

Misc.

Flattr this

RSS Feed

r3dux twitter feed



“The sooner you fall behind, the more time you'll have to catch up.”

rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox