Particle system #1 - Basic particles
By Andreas, 19 April, 2010

As I am coming from a background of gameprogramming (and originally from the demo scene in the 90´s) am I very fond of small tips and tricks to create nice special effects. There are few project that I see out there that couldn’t be spiced up with a nice particle system so I decided to go through some basics of particle systems and how they can be used to create a variety of effects. In this first “chapter” I will just go through the basics of a system and how it works and then later on create a more flexible system that can be used in oh so many situations.

Now lets look at what we will create today:

For a programmer used to flash (which is a very “visual” language) it’s not especially hard to understand the concept of particles as it is nothing less than Displayobjects being placed on screen and adjusted using it’s normal parameters such as scale, rotation, color and position. In this exampel you see two different particle systems. One with the stars, adjusting their scale, alpha and position to create the illusion of the camera travelling forward in an endless space. The other system is the supernova with a few “particles” being placed in the center, scaled, rotated and then fading out with the alpha. Everything is blended with the awesome ADD-blendmode which must be the most used blendmode in any game/demo with some self respect. Both these systems origins from the center of the scene/stage so the Main class of this small app is probably very basic.


package
{
 import flash.display.Sprite;
 import se.xcom.effects.particle.NovaEmitter;
 import se.xcom.effects.particle.StarEmitter;

public class LiteTest extends Sprite
 {
 public function LiteTest()
 {
 super();

 // create the emitters and adding it to the middle of scene.
 var nova:NovaEmitter = new NovaEmitter();
 nova.x = stage.stageWidth*.5;
 nova.y = stage.stageHeight*.5;
 nova.scaleX = 2;
 nova.scaleY = 2;

 var stars:StarEmitter = new StarEmitter()
 stars.x = stage.stageWidth*.5;
 stars.y = stage.stageHeight*.5;

 addChild(nova);
 addChild(stars);
 }
 }
}

Ok, lets take a look at one of the systems. All particle systems have some kind of “emitter”. You can see it as an object on the scene that is producing particles. It is not visible itself but the particles it “emits” is (most of the time) visible. The emitter is somehow the engine that decides how many particles is being generated, how they behave, rotate, scale etc.. You can see it as a located factory in the screen producing particles. Sometimes it shoots the particles out from the center of itself (just like nova in this example) but it could on the other hand let particles be spawned all around itself just like the stars system.



package se.xcom.effects.particle
{
 import flash.display.BlendMode;
 import flash.display.Sprite;
 import flash.events.TimerEvent;
 import flash.utils.Timer;

 import gs.TweenMax;
 import gs.easing.Linear;

public class NovaEmitter extends Sprite
 {
 private var emitTimer:Timer

 // Time until next particle is emitted (ms).
 private static const EMIT_TIME:Number = 1500

 public function NovaEmitter()
 {
 super();
 emitTimer = new Timer(EMIT_TIME)
 emitTimer.addEventListener(TimerEvent.TIMER,onTimer)
 emitTimer.start()

 // creating a few particles to begin with.
 for (var i:uint=0;i < 5;i++)
 {
 createParticle()
 }
 }

 public function onTimer(e:TimerEvent)
 {
 createParticle()
 }

 private function createParticle(prog:Number = 0)
 {
 var part:Sprite = new Particle() // is a simple bitmap in flash library converted as a Sprite.

 // modifying particle.
 part.rotation = Math.random()*360
 part.scaleX = part.scaleY = 0.3+Math.random()*0.3
 part.blendMode = BlendMode.ADD
 part.alpha = 0
 var time:Number = Math.random()*7+5
 var rot:Number = Math.random()*180-90
 var scale:Number = Math.random()*1.6+0.6
 var posX:Number = Math.random()*50-25
 var posY:Number = Math.random()*50-25

 addChild(part)

 TweenMax.to(part,time,{x:posX,y:posY,rotation:String(rot),scaleX:scale,scaleY:scale,ease:Linear.easeOut, onComplete:killParticle,onCompleteParams:[part]})
 TweenMax.to(part,time/4,{alpha:1,overwrite:false})
 TweenMax.to(part,time*2/3,{delay:time/3,alpha:0,overwrite:false})
 }

 private function killParticle(obj:Sprite)
 {
 this.removeChild(obj)
 obj = null
 }
 }
}

As you can see the Nova-system creates a new particle every 1.5 sec. It sets a lot of random parameters for the sprite and then just tweens it using the badass library TweenMax (which can be found here) and then destroy’s itself neatly afterwards. Straightforward huh? The secret with the fluid animation of the nova is mostly because of the blendmode that I previously mentioned.
ADD does exactly what it says. It adds two colours (their rgb-values) into one. this is great for oh so many purposes. First of all it never gives you any black corners as if it’s black, it just shows the colour behind. Also it is a great way to mask out an effect with a black background without using alphachannels. In fact this is a much faster way for the processor to handle masking than alphachannels are.

Now let’s look at the stars. They are not different at all.


package se.xcom.effects.particle
{
import flash.display.BlendMode;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;

import gs.TweenMax;
import gs.easing.Quad;

public class StarEmitter extends Sprite
 {
 private var emitTimer:Timer
 private static const STAR_TIME:Number = 4
 private static const EMIT_TIME:Number = 1

 public function StarEmitter()
 {
 super();
 emitTimer = new Timer(EMIT_TIME)
 emitTimer.addEventListener(TimerEvent.TIMER,onTimer)
 emitTimer.start()

 // initiating with some stars
 for (var i:uint=0;i < 40;i++)
 {
 createParticle()
 }
 }

 public function onTimer(e:TimerEvent)
 {
 for (var i:uint=0;i < 3;i++)
 {
 createParticle()
 }
 }

 private function createParticle()
 {
 var part:Sprite = new Star() // is a simple bitmap in flash library converted as a Sprite.

 // modifying particle.
 var z:Number = Math.random(); // z = 1 means it is in the same Z as the camera
 var posX:Number = (Math.random()*1500-750)
 var posY:Number = (Math.random()*1500-750)

 part.blendMode = BlendMode.ADD
 part.alpha = 0
 part.scaleX = part.scaleY =0
 part.x = posX*z
 part.y = posY*z
 addChild(part)

 var t:Number = STAR_TIME*(1-z)
 var endScale:Number = Math.random()

 TweenMax.to(part,t,{x:posX,y:posY,scaleX:endScale,scaleY:endScale,ease:Quad.easeIn, onComplete:killParticle,onCompleteParams:[part]})
 TweenMax.to(part,t/2,{alpha:1,overwrite:false})
 TweenMax.to(part,t*1/2,{delay:t*1/2,alpha:0,overwrite:false})
 }

 private function killParticle(obj:Sprite)
 {
 this.removeChild(obj)
 obj = null
 }
 }
}

The only difference in this class is the way the particles are positioned and adjusted in the tweens. To give you the illusion of depth/moving forward, I create a fake Z-axis value with the span of 0-1. 1 would be closest to the viewer and positioning the star at posX on the screen with the full scale of 1. Any other lower z-value brings the star towards the middle of the screen and also lowers the scale giving the illusion of the star moving further away from the viewer. Some fancy adjusting with alpha tweening in and out + a nice easeIn so the stars that is further away moves more slowly adds to the illusion even more.

Now, there is a great basic example how to use a few particles. Now is it a real system yet?? Well, there are a lot you could do to make it more dynamic. First of all we shouldn’t have to create 2 classes for these very similar classes. In the next part I ill give you the basics to create a more dynamic particle system where you can tweak a lot of parameters to be able to create snow, rain, fire, smoke, explosions etc… exciting, huh?
Have fun!

Rasberry Pi Image Streamer

Memory game

Kinect Robot

WaterFX - A much faster solution