Creating a Simple Flash Particle Emitter

Intro

Particles are essential in 3D. They can be used to represent fire, smoke, water, a swarm of bees, or a flock of birds. But presently Papervision doesn’t have a well-developed particle system. In the book, we develop a number of classes to enhance Papervision’s particle framework.

Particles systems typically have the following properties;

  • New particles are generated from an emitter
  • Each particle has unique attributes
  • Particles have a life time (or designated space) and afterwards are removed or reused
  • Particles are governed by scripts (classes that determine their behavior)
  • Particles are rendered

But in Flash the best way to handle particle lifetime is to regenerate them when their life time is over.

Click the image below to see the program in action. The particle emitter will follow your mouse, respond to gravity, bounce off a floor 3 times and then be regenerated back to the mouse pointer.

There are a number of key concepts here and particles are discussed in detail in the book. In this post, we shall lightly touch on the important concepts and provide you with all the code.

Particle Emitter
Particle Emitter

Demo

http://www.professionalpapervision.com/demos/web/pemitter/

Download

http://flex3cookbook2.googlecode.com/files/particleEmitter.zip

Discussion

Here are the key concepts:

Emitter

Creating an emitter is simple – you just tell the particles where to be created. In the code, we generate them at the mouse pointer with a small variation on velocity.

myParticle.ypos = mouseY-vpY;
myParticle.xpos = mouseX-vpX;

 

myParticle.vx = Math.random() * 6 – 3;
myParticle.vy = Math.random() * 6 – 6;
myParticle.vz = Math.random() * 6 – 3;

Regenerator

When a particle has outlived its lifetime we regenerate it by sending it back to the source. As discussed in previous posts regenerating particles is preferable based on how Flash handles memory resources.

myParticle.ypos = mouseY-vpY;
myParticle.xpos = mouseX-vpX;

 

z-Sorter

Since we are dealing with multiple particles we must sort them based on z-position.

private function sortZ():void
{
myParticles.sortOn(“zpos”, Array.DESCENDING | Array.NUMERIC);
for(var i:uint = 0; i < nummyParticles; i++)
{
var myParticle:ParticleEmitter = myParticles[i];
setChildIndex(myParticle, i);
}

Velocity

Velocity was added by incrementing it in the onEnterFrame loop.

myParticle.xpos += myParticle.vx;
myParticle.ypos += myParticle.vy;
myParticle.zpos += myParticle.vz;

Gravity

Gravity is created by iterating the y-velocity. To get smoke you would just change the sign of the gravity term and iterate upwards.

 

myParticle.vy += gravity;

 

Bounce

When the particle exceeds the floor then bounce is created by reversing velocity and doing an decimal multiplication on velocity.

 

myParticle.bounceNum++;
myParticle.vy *= bounce;

In the example above, bounce is equal to -.6 which reverses the velocity and reduces it exponentially.

Perspective Scaling

Thales theorem is used for perspective scaling in the z-coordinates.

var scale:Number = fl / (fl + myParticle.zpos);
myParticle.scaleX = myParticle.scaleY = scale;
myParticle.x = vpX + myParticle.xpos * scale;
myParticle.y = vpY + myParticle.ypos * scale;

Primitive

Even though this is not Papervision, it demonstrates how a primitive is set up. But the physics is in the primitive but Papervision does not have a physics engine. So the big questions is where should the physics go. Should it go on the primitive or on the DisplayObject3D. In this case, it is on the primitive, but putting it on the DisplayObject3D gives you the advantage of have the physics on all objects …not just primitives … more on this later.

In our primitive we have four possible shapes and they are selected randomly and thrown onto the stage using the switch case.

The random selector is on the main program side given by

var myParticle:ParticleEmitter= new ParticleEmitter(10, Math.random() * 0xffffff, Math.round(Math.random()*3));

where Math.round(Math.random()*3 selects from four possible particles found in the switch case from 0 to 3 on the primitive side.

switch(switchNum)

{

case 0:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawRect(0,0,2*radius,2*radius);
graphics.endFill();

break;

case 1:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();

break;

case 2:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawEllipse(0, 0, 2*radius, radius);
graphics.endFill();

break;

case 3:
graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawEllipse(0, 0, radius, 2*radius);
graphics.endFill();

break;

default:

trace(“warning – Particle material has no valid shape.”);

break;

}

}

To see the full source code click the more link below.

 

 

 

 

 

Particle Primitive (4 possible particles)

package primitive{
import flash.display.Sprite;

public class ParticleEmitter extends Sprite {
public var radius:Number;
private var color:uint;
public var xpos:Number = 0;
public var ypos:Number = 0;
public var zpos:Number = 0;
public var vx:Number = 0;
public var vy:Number = 0;
public var vz:Number = 0;
public var mass:Number = 1;
public var bounceNum:int=0;
public var switchNum:int;

public function ParticleEmitter(radius:Number=40, color:uint=0xff0000, switchNum:int=0 ) {
this.radius = radius;
this.color = color;
this.switchNum=switchNum;
init();
}
public function init():void {

switch(switchNum)

{

case 0:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawRect(0,0,2*radius,2*radius);
graphics.endFill();

break;

case 1:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();

break;

case 2:

graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawEllipse(0, 0, 2*radius, radius);
graphics.endFill();

break;

case 3:
graphics.lineStyle(0);
graphics.beginFill(color);
graphics.drawEllipse(0, 0, radius, 2*radius);
graphics.endFill();

break;

default:

trace(“warning – Particle material has no valid shape.”);

break;

}

}
}
}

Particle Emitter

package {
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.events.MouseEvent;

import primitive.ParticleEmitter;

public class Particles extends Sprite
{
private var myParticles:Array;
private var nummyParticles:uint = 100;
private var fl:Number = 250;
private var vpX:Number = stage.stageWidth / 2;
private var vpY:Number = stage.stageHeight / 2;
private var gravity:Number = 0.2;
private var floor:Number = 200;
private var bounce:Number = -0.6;

public function Particles()
{
init();
}

private function init():void
{

stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;

myParticles = new Array();
for(var i:uint = 0; i < nummyParticles; i++)
{
var myParticle:ParticleEmitter= new ParticleEmitter(10, Math.random() * 0xffffff, Math.round(Math.random()*3));
myParticles.push(myParticle);

myParticle.ypos =200;
myParticle.xpos = mouseX-vpX;
myParticle.zpos=0;
myParticle.vx = Math.random() * 6 – 3;
myParticle.vy = Math.random() * 6 – 6;
myParticle.vz = Math.random() * 6 – 3;
myParticle.visible=false;
addChild(myParticle);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function onEnterFrame(event:Event):void
{
for(var i:uint = 0; i < nummyParticles; i++)
{
var myParticle:ParticleEmitter = myParticles[i];
move(myParticle);
}
sortZ();
}

private function move(myParticle:ParticleEmitter):void
{
var radius:Number = myParticle.radius;

myParticle.vy += gravity;
myParticle.xpos += myParticle.vx;
myParticle.ypos += myParticle.vy;
myParticle.zpos += myParticle.vz;

if(myParticle.ypos > floor)
{
myParticle.bounceNum++;
myParticle.vy *= bounce;
if(myParticle.bounceNum>=4){
myParticle.ypos = mouseY-vpY;
myParticle.xpos = mouseX-vpX;
myParticle.zpos = 0;
myParticle.vx = Math.random() * 6 – 3;
myParticle.vy = Math.random() * 6 – 6;
myParticle.vz = Math.random() * 6 – 3;
myParticle.visible=true;
myParticle.bounceNum=0;
}
}

if(myParticle.zpos > -fl)
{
var scale:Number = fl / (fl + myParticle.zpos);
myParticle.scaleX = myParticle.scaleY = scale;
myParticle.x = vpX + myParticle.xpos * scale;
myParticle.y = vpY + myParticle.ypos * scale;

}
else
{
myParticle.visible = false;
}
}

private function sortZ():void
{
myParticles.sortOn(“zpos”, Array.DESCENDING | Array.NUMERIC);
for(var i:uint = 0; i < nummyParticles; i++)
{
var myParticle:ParticleEmitter = myParticles[i];
setChildIndex(myParticle, i);
}
}
}
}

About these ads

One Response to Creating a Simple Flash Particle Emitter

  1. […] > Creating a Simple Flash Particle Emitter « Professional Papervision3D Book […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: