AS3 Particle System
With
a gleam in their eye developers have embraced the newest version of
Flash. Why? Because of this lovely little gal named Actionscript 3
(totally hot), and boy does she move fast. The bad thing is she likes
the exact opposite kind of man that Actionscript 1 and 2 did:
developers (who are real men anyway). Not to worry, as long as you say
the right things I'm sure you'll hit it off just fine.
And
it's true, Actionscript 3 is what a lot of developers had hoped for
with version 2 and so much more. Movieclips and Actionscript can
finally work in true harmony and there's no better way to show this
relationship is by making a simple particle system.
Our
system will consist of three things: the environment, a generic
particle, and a specific particle. The environment will be the flash
file itself where we make the rules on how the particles behave: where
they're created and how they're created. The generic particle will
contain the basic framework for our specific particle: a trajectory and
position that's updated by variables supplied via the environment. The
specific particle will actually be what we're generating and because it
has unique aspects is best as a subclass of our generic particle.
Lets
start out by creating the base of our system: the generic particle.
Without this the rest of our system couldn't be created. Starting out
by first thinking what the generic particle needs. In Actionscipt 3 you
have to import most things so it's best to think ahead. Lets see, we
need a way to update the particle, preferably time based, and it needs
to be able to be displayed as well, it also needs to store x,y
coordinate data. Thankfully there are classes just for that: Timer,
TimerEvent, Point, and MovieClip.
[as]package{
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.display.MovieClip;[/as]
Simple
enough, now for the tough part. What input from the environment does
our particle need? For our purposes we are going to be thinking simple
physics. That means four things: a trajectory, a stored position, a
constant for gravity, and friction. We also need to store these values
specific to the particle.
[as]public class Particle extends MovieClip{
protected var position:Point;
protected var vector:Point;
private var gravity:int;
private var friction:Number;
public function Particle($position:Point, $vector:Point, $gravity:int, $friction:Number){
position = $position;
vector = $vector;
gravity = $gravity;
friction = $friction;[/as]
With
the basic values added to our particle it's now time to update their
values via a timer. Timers are the new setInterval; I prefer using
Timers over frame based events myself. It's quite straight forward.
First a timer needs to be created that will trigger at a set interval.
Then the particle needs to listen to that timer for that trigger and
call a method once it happens. First we have to add a class variable
for our timer.
[as]protected var update_i:Timer;[/as]
Then we can create a timer and add a listener in the constructor that's currently open to finish it off.
[as] update_i = new Timer(25); //25ms for smooth movement
update_i.addEventListener(TimerEvent.TIMER, update, false, 0, true);
update_i.start();
}[/as]
The
event listener is going to want to trigger a public method called
update so we better get onto creating that. When writing handlers in
Actionscript 3 they must receive an event object as their first
parameter. Now, when our particle moves three things happen: the
position gets updated via the movement vector, the y portion of the
vector gets affected by gravity, and the x portion of the vector gets
affected by the friction.
[as]public function update($evt:TimerEvent):void{
//Apply The Vector To The Position
position.x += vector.x;
position.y += vector.y;
//Apply gravity
vector.y += gravity;
//Apply Friction!
vector.x *= friction;
}[/as]
Great now the generic particle class is done, time to close the class and package and move onto the specific particle.
[as]}
}[/as]
For
the specific particle we need to create a graphic, for all intensive
purposes a ball will suffice. Create a new movieclip in the library and
draw a circle in it. Once you have drawn the movieclip, right click on
it in the library and choose linkage. You'll notice that the linkage
window is now different and instead of an identifier it asks for a
class. Input "Ball" into the class textbox and press the OK button.
Ignore any warning flash gives you, we'll write a class soon enough.
The
Ball class will be similar to the particle class (it is a subclass
after all). Remember, the Particle class still needs all the parameters
from the environment so the Ball class has to pass them on.
[as]package{
import flash.events.TimerEvent;
import flash.geom.Point;
public class Ball extends Particle{
public function Ball($position:Point, $vector:Point, $gravity:int, $friction:Number){
super($position, $vector, $gravity, $friction); //Pass the torch[/as]
We have to also set the initial position of the Ball clip.
[as]//Set Initial Position
x = position.x;
y = position.y;[/as]
As
you could see in the Particle class we changed the position variable
but never actually modified the x and y value of the clip. This is what
the Ball class will be responsible for. To archive this all that's
needed is to listen, again, for a timer event and call a method. Then,
we're done!
[as] update_i.addEventListener(TimerEvent.TIMER, setPosition, false, 0, true);
}[as]
public function setPosition($evt:TimerEvent):void{
x = position.x;
y = position.y;
}
}
}[/as]
Now
it's finally some time for a little fun. Lets get these babies moving.
The environment will be, what else, our main stage. On the first frame
to be exact. First things first, a timer and a listener.
[as]var ballTimer:Timer = new Timer(25);
ballTimer.addEventListener(TimerEvent.TIMER, throwBall, false, 0, true);
ballTimer.start();[/as]
Next we set the environment variables for our balls.
[as]//Environment Variables
var gravity:int = 1.5;
var friction:Number = .85;[/as]
For
the throwBall function we can have a little fun and use the mouseX and
mouseY properties and some Math.random to make a fountain type effect.
[as]function throwBall($evt:TimerEvent):void{
var tBall:Ball = new Ball(new Point(mouseX, mouseY), new Point(
(Math.random()-Math.random())*5, -Math.random()*8), gravity, friction);
addChild(tBall);
}[/as]
Test
your movie and there you have it, some particles. Not the most
impressive thing in the world but the concepts we covered (whether you
knew it or not) are important. Separate what is different and keep it
separate. We had three different pieces to this puzzle, the Particle
class, the Ball class, and the environment. By keeping each of these
separate we can easily change and modify the behavior or look of the
particles we're creating. With some tweaking you can easily create
yourself a nice little sparkler like this.