ActionScript 3.0 Particle Systems #1: Random Motion

I’ve been working on getting my ActionScript 3 up to speed by going through a stack of videos purchased from learnflash.com, and fair play, I’m really quite enjoying it all.

Expect a couple of these kinds of things over the coming days and weeks :D

That Craig chap off learnflash really knows his stuff – top bloke.

Also, source code and flash files after the jump if you’re that way inclined…

Update I’ve updated all the code to make it start paused, and the animation can be toggled on and off with the space bar. Also, all Particle objects are now instantiated to a vector instead of just called by the same instance name over and over in a loop (which was just horrid code) so now we can access each particle individually through it’s unique element number should we so wish. I guess I was just really tired yesterday after doing like 13 hours of flash and I wanted to post something before I went to bed. Kinda rushed it – oh wells!

Flash File (ActionScript 3.0) Code:

import flash.events.KeyboardEvent;
import Particle;
 
// Define our vector (just a dynamic array with a specied type in AS3!)
var particleVect:Vector.<Particle> = new Vector.<Particle>;
 
// Define our number of particles to display on the screen and a start/stop animation flag
var numberOfParticles:uint = 200;
var toggleAnimation = false;
 
// Create our controls message, center it and add it to the screen
var msg:ControlsMessage = new ControlsMessage();
msg.x = stage.stageWidth / 2;
msg.y = stage.stageHeight / 2;
addChild(msg);
 
// Create a flag to only show our controls message once
var showMsg:Boolean = true;
 
function addParticles():void
{
	// Create however many particles we've entered into our numberOfParticles variable
	for (var loop:uint = 0; loop < numberOfParticles; loop++) {
 
		// Create a new instance of Particle and add it to our Vector of Particles
		particleVect.push(new Particle());
 
		// Randomise the x (horizontal) and y (vertical) locations on stage 
		particleVect[loop].x = Math.random() * stage.stageWidth;
		particleVect[loop].y = Math.random() * stage.stageHeight;
 
		// Randomise alpha
		particleVect[loop].alpha = Math.random();
 
		// Randomise size between 0% and 100% (i.e. between 0.0 and 1.0)
		var sizeScale:Number = Math.random(); 
		particleVect[loop].scaleX = sizeScale;
		particleVect[loop].scaleY = sizeScale;	
 
		// Add the particle to the stage
		addChild(particleVect[loop]);
 
	} // End of for loop
 
} // End of addParticles function
 
function removeParticles():void
{
	// Remove however many particles we're working with from the stage
	for (var loop:uint = 0; loop < numberOfParticles; loop++) {
 
		// Call our custom destructor to unbind any particle eventListeners
		particleVect[loop].ParticleDestructor();
 
		// Remove the particle from the stage
		removeChild(particleVect[loop]);		
 
	}
	// Remove all particles the vector.
	// We can't just use "particleVect = null;" or we'll lose our global instance of the vector!
	while(particleVect.length > 0) {
		particleVect.pop();
	}
 
} // End of removeParticles function
 
function particleController(e:KeyboardEvent):void
{
	// If the animation is stopped, add the particles and flip the flag
	if (toggleAnimation == false) 
	{
		addParticles();
		toggleAnimation = true;
 
		// Only remove message after first display, as it'll only be on stage once
		if (showMsg == true) 
		{
			showMsg = false;
			removeChild(msg);
		}
	}
	else {
		// Otherwise animation must be running and we want it to stop, so remove the
		// particles and flip the flag
		removeParticles();
		toggleAnimation = false;
	}
 
} // End of particleController function
 
// With all our functions in place, bind the particle controller function to a keypress
stage.addEventListener(KeyboardEvent.KEY_DOWN, particleController);

ActionScript 3.0 Particle Class Code:

package
{
	// Import the MovieClip and Event classes
	import flash.display.MovieClip;
	import flash.events.Event;
 
	public class Particle extends MovieClip
	{
		// Define our class properties
		var xSpeed:Number;
		var ySpeed:Number;
		var alphaDecay:Number;
		var fadeBack:Boolean;
 
		// Class Constructor
		function Particle():void
		{
			// Add an event listener to each instance of a particle so that it's updated every
			// time there's a new frame (default: 24 times a second, i.e. 24fps)
			this.addEventListener(Event.ENTER_FRAME, updateParticle);
 
			// Randomise the x and y speed of the particle between -5 and 5 on instantiation
			// and set a random alpha (transparency) decay speed
			this.xSpeed = (Math.random() * 10) - 5;
			this.ySpeed = (Math.random() * 10) - 5;			
			this.alphaDecay = Math.random() / 100;
 
			// Initially, our particle is not fading back in
			this.fadeBack = false;			
		}
 
		// Unbind the particle's ENTER_FRAME event listener when we destroy it
		// I can't believe AS3 doesn't support destructors... extra weak sauce =/
		public function ParticleDestructor():void
		{
			this.removeEventListener(Event.ENTER_FRAME, updateParticle);
		}
 
		// Function to update a particle, bound to Event.ENTER_FRAME, so called once per frame 
		private function updateParticle(e:Event):void
		{
			// Add our randomised x and y speeds to our particle position
			this.x += xSpeed;
			this.y += ySpeed;
 
			// Subtract a small amount from our object's alpha so it fades out
			this.alpha -= this.alphaDecay;
 
			// Reset particle properties when it's faded out so much it's completely transparent
			if (this.alpha <= 0) {
				// Re-randomise the x and y locations of our particles 
				this.x = Math.random() * stage.stageWidth;
				this.y = Math.random() * stage.stageHeight;
 
				// Re-randomise our x and y speeds
				this.xSpeed = (Math.random() * 10) - 5;
				this.ySpeed = (Math.random() * 10) - 5;
 
				// Set out fadeBack flag to true
				this.fadeBack = true;
			}
 
			// When a particle has completely faded out (fadeBack == true), fade it back in quickly
			if (this.fadeBack == true) {
				this.alpha += 0.15;
 
				// When we're fully opaque again stop making any further fadeBack alpha changes
				if (this.alpha >= 1) {
					this.fadeBack = false;
				}
			}
 
		} // End of updateParticle function
 
	} // End of Particle class
 
} // End of package

Adobe Flash CS4 files for the above can be found: here.

20 thoughts on “ActionScript 3.0 Particle Systems #1: Random Motion”

  1. hello,

    i just discovered your site and find it really great. i am learning flash/actionscript now and want to program some interesting animations but i think to accomplish this i have to gain more knowledge about particle moving math and stuff. so I’m hoping this particle series of yours help me on this a little bit.
    if you’re interested how my particles look like you can check it here:
    http://kelemen.webs.com/myparticles/particles.html

    i have a question to ask: in performance’s point of view which is better: instantiating a circle movie clip or generating circles at runtime?

    1. Hey oxid – glad you found some of the ActionScript posts of use!

      As for your question – I had no idea, so I coded something up to find out…

      As I’m trying to do a post-per-day I’ve written it all up and scheduled it to post tomorrow (Saturday the 13th of Feb, 00:01 GMT GMT+11) – and I think it’ll answer your question quite comprehensively! :D

      P.S. Like your particle stuff – keep up the good work!

  2. hi… I am working as a flash trainee programmer in Chennai, and actioscript volunteer too. Your animations are simply great…….. thanks..

  3. hello

    this is great! i just love it but it’s giving me a error :( ERROR 1084: Syntax error: expecting identifier before lessthan.

    SOURCE:

    var particleVect:Vector.<Particle> = new Vector.<Particle>;

    how do i make it work right?

    thanks in advance

    edit: Modified source line to show the Particle part within angle brackets -r3dux

    1. Hi akira_lee,

      The problem sounds like Flash doesn’t know about the Particle class somehow.. If you’ve copied and pasted the code, did you paste the second lot of code (Particle.as) into a file called Particle.as? If not, try that. Also, both files (the Particle.as -and- the RandomMotion.fla file) have to be in the same directory for it to work.

      Another option is to just grab the provided source code from the link at the bottom of the article (this one) and have a play with the code from that.

      Hope you get it sorted!

      r3dux

    1. Thanks for sending me a link to what you’ve done with the source – looks great!

      The only thing I might add is that the flash CPU usage is a little high because of the large stage size, so to try to deal with that a little it might be worth adding the following to your .fla file near the top, either:

      stage.quality = StageQuality.MEDIUM;

      or

      stage.quality = StageQuality.LOW;

      This will trade-off visual fidelity for lower CPU/GPU usage, and you might be surprised to see that the results aren’t really that noticeable! It’s certainly worth a shot! Another possibility is to lower the frame rate and compensate for any jerkyness of the particles by lowering the movement speed.

      Oh, and when you’re embedding your flash into the page, if you haven’t already – have a bit of an experiment with the the wmode=”gpu” and wmode=”direct” attributes of the embedding code! This can strongly affect CPU usage, too!

      Best wishes & again, great work on the site – it looks superb!

      r3dux

  4. Ok so this works great but I want to remove the keystroke and have the particles start automatically. I’ve tried adjusting the code but have had no luck. What do I remove to make this happen?

    1. Hi Lindsay,

      Instead of me trying to outline all the changes you need to make I’ve done two alternate versions of the .fla code for you:
      No Key To Start – which will start the animation on execution, but still allows you to toggle the particles on/off via a keypress, and
      Non-Interactive – which just kicks off the animation and never stops or allows the user to stop it.

      Just replace the code in your .fla file with the code from your link of choice above, and you should be hot to trot =D

    1. Either draw the objects you want on top last, or place the objects on top on a layer which is above the layer with the particles in the timeline.

  5. i’m using the non-interactive script and it works great.

    is there any way to control when it starts and stops either in the timeline or in action script??

    thanks! beautiful animation!

    Mike

  6. nevermind! figured it out. just copied and pasted the removeParticles function and that worked perfectly.

    ok, what about tweening the alpha of the animation so that it fades in?

    thanks! :)

    1. Hi Michael,

      To tween the alpha of the entire animation, the easiest way I can think of to do it is to add the particles to a MovieClip (instead of adding them directly to the stage) and fade the MovieClip in/out as you please.

      So instead of having this in the addParticles function:

      // Add the particle to the stage
      addChild(particleVect[loop]);

      You might have:

      // *** Put this somewhere near the top of script in the .fla ***
      // Create a MovieClip to hold the particles
      var particleMC:MovieClip = new MovieClip;
       
      // Make the particleMC completely transparent initially so we can fade it in later
      particleMC.alpha = 0;
       
      // Add the particleMC to the stage
      addChild(particleMC);
       
      // *** Put this in the addParticles function to replace adding the particles to the stage with adding them to the particleMC ***
      // Add the particle to the particleMC
      particleMC.addChild(particleVect[loop]);

      You can then twiddle the particleMC.alpha property to fade it in/out as you like, which should in turn fade in/out all the particles drawn in it!

      Actually, I wanted to make sure that it worked before commenting, and it does – here’s what I used:

      import Particle;
       
      // Define our vector (just a dynamic array with a specied type in AS3!)
      var particleVect:Vector.<Particle> = new Vector.<Particle>;
       
      // Define our number of particles to display on the screen and a start/stop animation flag
      var numberOfParticles:uint = 200;
      var toggleAnimation = false;
       
      // Create a MovieClip to hold the particles
      var particleMC:MovieClip = new MovieClip;
       
      // Set it to be completely transparent
      particleMC.alpha = 0;
       
      // Add it to the stage
      addChild(particleMC);
       
      // Create a frame counter and initialise it to zero
      var frameCount:uint = 0;
       
      function addParticles():void
      {
      	// Create however many particles we've entered into our numberOfParticles variable
      	for (var loop:uint = 0; loop < numberOfParticles; loop++) {
       
      		// Create a new instance of Particle and add it to our Vector of Particles
      		particleVect.push(new Particle());
       
      		// Randomise the x (horizontal) and y (vertical) locations on stage 
      		particleVect[loop].x = Math.random() * stage.stageWidth;
      		particleVect[loop].y = Math.random() * stage.stageHeight;
       
      		// Randomise alpha
      		particleVect[loop].alpha = Math.random();
       
      		// Randomise size between 0% and 100% (i.e. between 0.0 and 1.0)
      		var sizeScale:Number = Math.random(); 
      		particleVect[loop].scaleX = sizeScale;
      		particleVect[loop].scaleY = sizeScale;	
       
      		// Add the particle to the stage
      		particleMC.addChild(particleVect[loop]);
       
      	} // End of for loop
       
      } // End of addParticles function
       
      // Function to fade in the particleMC
      function fadeIn(e:Event):void
      {
      	// Fade in over 100 frames. Once the frameCount is 100, stop incrementing
      	// it because the alpha will be 1.0 (full opacity)
      	if (frameCount < 100)
      	{
      		frameCount++;
      		particleMC.alpha = frameCount / 100.0;
       
      	}
      	else // Unregister the fadeIn function when we've finished fading in
      	{
      		stage.removeEventListener(Event.ENTER_FRAME, fadeIn);
      	}
      }
       
      // Add the particles
      addParticles();
       
      // Add an eventlistener to fade in the particleMC
      stage.addEventListener(Event.ENTER_FRAME, fadeIn);
       
      // Stop the animation here - the particles themselves will update on each
      // new frame as per the EventListener specified in the particle constructor
      stop();

      Hope this helps!

  7. Hello!

    I think I did it right, but I get an error, something like 1172: The definition __AS3__.vec:Vector not found. on Particle.as, Line 1.

    Do you know what the problem may be?

    Thanks!

  8. Oh, I found it. For somewhat reason I was using an older version of Flash Player when compiling. Sorry!

    But thanks anyway for sharing this! :D

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.