1 [FL]Flash Tutorial Manipulating Particle Motion with Stardust Particle Wed Sep 22, 2010 11:12 am
Admin
Admin
Tutorial Details
Tweet
Share
Download Source Files
Demo View It Online
This is the second part of this tutorial. I’m going to show you how to manipulate particle motion with deflectors.
Prior knowledge of motion basics and vector fields is required. I highly recommend that you complete the first part of this tutorial before moving on.
Final Result Preview
Take a look at the final result we will be working towards. It’s an example of a floor effect, with particles bouncing off the floor.
Deflectors
Pretty much like gravity fields, a deflector takes a particle’s current motion data as input. Afterwards, the deflector overwrites the particle’s motion with its output, only that the output now contains velocity data in addition to position data. Thus, in 2D space, a deflector’s output is a 4D vector; the first two components of the 4D vector represent the x- and y-component of the position vector (denoted x and y), respectively, and the last two components represent the x- and y-component of the velocity vector (denoted vx and vy).
How To Use Deflectors
Remember the Field class and the Gravity action from the first part of this tutorial? Well, the procedure is similar. You create Deflector objects that manipulate particle motions, and then add them to the Deflect action, just like you would add Field objects to the Gravity action. Now let’s look at a quick example.
Floor Effect
In this example, we’re going to use the LineDeflector class to create a particle-bouncing-off-floor effect. A line deflector essentially simulates an infinitely long line in 2D space, with one side being open space, and the other side solid; particles are only allowed to be in the open space and not allowed in the solid space. When particles come from the open space side, hitting the line, they’ll bounce back. The Particle.collisionRadius property, representing the radius of a particle, is taken into account.
The line deflector uses a normal vector and a point the line passes through in 2D space to determine the line. Here’s an illustration to give you a better idea. [You must be registered and logged in to see this image.]
Step 1: Floor Effect Circle Symbol
Create a new Flash document, draw a circle of radius of 10, and then convert it to a symbol, exported for ActionScript with a class name Circle. [You must be registered and logged in to see this image.]
Step 2: Floor Effect The Document Class
Create an AS file for the document class. The class creates an emitter and a renderer. If you feel like needing a refresher on Stardust’s basic usage, you may check out this tutorial. view source
print?
The emitter class is shown below. It basically shoots out circle particles and the particles are affected by a uniform gravity field, pointing downward. view source
print?
Now you have created an effect with particles shooting out from the center of the stage, being pulled down by gravity. This is what it looks like: Milestone View It Online
Step 3: Floor Effect Add the Deflector
Add the folloing code in the emitter constructor. It creates a line deflector, adds it to the Deflector action, and then adds the action to the emitter, thus activating the deflector effect. The first two constructor paramters for the LineDeflector class is the coordinate of a point on the line, and the last two parameters are the x- and y-components of the line’s normal vector. The Deflector.bounce property determines the “bounciness” of the line, 1 causing complete rebound, and 0 meaning no rebound at all. view source
print?
You may also draw a visual representation of the line on the stage to have a better look. [You must be registered and logged in to see this image.]
Alright, we’re done with this example. Now let’s take a look of our final outcome. Milestone View It Online
Bounding Box
In this example, we’re going to use the BoundingBox deflector to constrain particles inside a rectangular area.
Step 1: Bounding Box The Emitter Class
The document class remains the same as the previous example, but we are going to change the emitter class. This is the base emitter class of this example. Compared to the emitter class in the previous example, the SteadClock is changed to a ImpulseClock to instantly create 20 particles at the beginning, the position zone is changed from a single point to a rectangular zone that matches the stage size, the Velocity initializer is slowed down a bit, the Life initializer is removed because we want particles to stay permanently on the stage, the Age and DeathLife actions are in turn not required and removed, and the ScaleCurve is also removed. Some imports are also added and removed; you may just copy the code below for convenience. view source
print?
Step 2: Bounding Box Add the Deflector
Pretty much like the previous example, we now add the following code in the emitter constructor to use the Deflect action, only that this time we use the BoundingBox deflector to constrain particles inside a rectangular region that matches the stage size.
google_protectAndRun("render_ads.js::google_render_ad", google_handleError, google_render_ad);
view source
print?
Step 3: Bounding Box Test the Movie
That’s it. Nothing much is changed, and now we have constrained particles in a bounding box. Test the movie and you shall see the result. Milestone View It Online
Custom Deflectors
Now, we are going to create custom deflectors on our own. Let’s first understand the Deflector class we’re about to extend.
The Deflector class is the base class for all deflectors. In order to create custom deflectors, you should extend this class and override the calculateMotionData4D() method, and then return a MotionData4D object representing the 4D vector output of the deflector. The input at your disposal, just like the Field class, is included in the Particle2D object passed into the method as parameter. You may use this Particle2D object to determine your output. By the way, if this method returns a null value, the Deflect action would assume that you do not want to change the current particle’s motion, ignore the particle, and then go on to processing the next particle.
For instance, the following deflector would rotate each particle’s velocity vector by one degree clock-wise. view source
print?
Tube Deflector Effect
In this example, we are going to extend the Deflector class and create our own deflector, simulating a tube, which is essentially two line deflectors sandwiching a tube-shaped free space. [You must be registered and logged in to see this image.]
Step 1: Tube Deflector Effect The Emitter Class
Copy the Flash document, along with the Circle symbol, and the document from the first example. Here we are going to create another emitter class, still named CircleEmitter. This time the emitter emits particles from the center of the stage, and no gravity field is applied. view source
print?
Step 2: Tube Deflector Effect The Tube Deflector
Now we are going to create our tube deflector class. Details are explained in comments. view source
print?
Step 3: Tube Deflector Effect Add the Deflector
You should know what we’re going to do next very well by now. That’s right, we’re going to add the deflector to a Deflect action and then add the action to the emitter. Add the following code in the emitter constructor. view source
print?
Step 4: Tube Deflector Effect Test the Movie
You can now test the movie. Again, you may also draw some visual representation of the deflector on the stage for a better look. Milestone View It Online
Conclusion
This is the end of the entire tutorial. In the first part you have learned about gravitational fields. In the second part, you have learned the concept of deflectors and the actual usage of the Deflect action. Also, you’ve learned how to extend the Deflector class to create custom deflectors. Now you’re able to perform advanced particle motion manipulation in Stardust.
Thank you very much for reading!]
- Difficulty: Intermediate
- Program: Flash
- Estimated Completion Time: 40 mins
Tweet
Share
Download Source Files
Demo View It Online
This is the second part of this tutorial. I’m going to show you how to manipulate particle motion with deflectors.
Prior knowledge of motion basics and vector fields is required. I highly recommend that you complete the first part of this tutorial before moving on.
Final Result Preview
Take a look at the final result we will be working towards. It’s an example of a floor effect, with particles bouncing off the floor.
Deflectors
Pretty much like gravity fields, a deflector takes a particle’s current motion data as input. Afterwards, the deflector overwrites the particle’s motion with its output, only that the output now contains velocity data in addition to position data. Thus, in 2D space, a deflector’s output is a 4D vector; the first two components of the 4D vector represent the x- and y-component of the position vector (denoted x and y), respectively, and the last two components represent the x- and y-component of the velocity vector (denoted vx and vy).
How To Use Deflectors
Remember the Field class and the Gravity action from the first part of this tutorial? Well, the procedure is similar. You create Deflector objects that manipulate particle motions, and then add them to the Deflect action, just like you would add Field objects to the Gravity action. Now let’s look at a quick example.
Floor Effect
In this example, we’re going to use the LineDeflector class to create a particle-bouncing-off-floor effect. A line deflector essentially simulates an infinitely long line in 2D space, with one side being open space, and the other side solid; particles are only allowed to be in the open space and not allowed in the solid space. When particles come from the open space side, hitting the line, they’ll bounce back. The Particle.collisionRadius property, representing the radius of a particle, is taken into account.
The line deflector uses a normal vector and a point the line passes through in 2D space to determine the line. Here’s an illustration to give you a better idea. [You must be registered and logged in to see this image.]
Step 1: Floor Effect Circle Symbol
Create a new Flash document, draw a circle of radius of 10, and then convert it to a symbol, exported for ActionScript with a class name Circle. [You must be registered and logged in to see this image.]
Step 2: Floor Effect The Document Class
Create an AS file for the document class. The class creates an emitter and a renderer. If you feel like needing a refresher on Stardust’s basic usage, you may check out this tutorial. view source
print?
01 | package { |
02 | import flash.display.Sprite; |
03 | import flash.events.Event; |
04 | import idv.cjcat.stardust.common.emitters.Emitter; |
05 | import idv.cjcat.stardust.common.renderers.Renderer; |
06 | import idv.cjcat.stardust.twoD.renderers.DisplayObjectRenderer; |
07 |
08 | public class FloorEffect extends Sprite { |
09 |
10 | private var emitter:Emitter; |
11 | private var renderer:Renderer; |
12 |
13 | public function FloorEffect() { |
14 | emitter = new CircleEmitter(); |
15 | renderer = new DisplayObjectRenderer(this); |
16 | renderer.addEmitter(emitter); |
17 |
18 | addEventListener(Event.ENTER_FRAME, mainLoop); |
19 | } |
20 |
21 | private function mainLoop(e:Event):void { |
22 | emitter.step(); |
23 | } |
24 | } |
25 | } |
The emitter class is shown below. It basically shoots out circle particles and the particles are affected by a uniform gravity field, pointing downward. view source
print?
01 | package { |
02 | import idv.cjcat.stardust.common.actions.Age; |
03 | import idv.cjcat.stardust.common.actions.DeathLife; |
04 | import idv.cjcat.stardust.common.actions.ScaleCurve; |
05 | import idv.cjcat.stardust.common.clocks.SteadyClock; |
06 | import idv.cjcat.stardust.common.initializers.Life; |
07 | import idv.cjcat.stardust.common.initializers.Scale; |
08 | import idv.cjcat.stardust.common.math.UniformRandom; |
09 | import idv.cjcat.stardust.twoD.actions.Gravity; |
10 | import idv.cjcat.stardust.twoD.actions.Move; |
11 | import idv.cjcat.stardust.twoD.emitters.Emitter2D; |
12 | import idv.cjcat.stardust.twoD.fields.Field; |
13 | import idv.cjcat.stardust.twoD.fields.UniformField; |
14 | import idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; |
15 | import idv.cjcat.stardust.twoD.initializers.Position; |
16 | import idv.cjcat.stardust.twoD.initializers.Velocity; |
17 | import idv.cjcat.stardust.twoD.zones.LazySectorZone; |
18 | import idv.cjcat.stardust.twoD.zones.SinglePoint; |
19 |
20 | public class CircleEmitter extends Emitter2D { |
21 |
22 | public function CircleEmitter() { |
23 | super(new SteadyClock(1)); |
24 |
25 | //initializers |
26 | addInitializer(new DisplayObjectClass(Circle)); |
27 | addInitializer(new Life(new UniformRandom(60, 10))); |
28 | addInitializer(new Position(new SinglePoint(320, 100))); |
29 | addInitializer(new Velocity(new LazySectorZone(8, 4))); |
30 | addInitializer(new Scale(new UniformRandom(1, 0.4))); |
31 | addInitializer(new CollisionRadius(10)); |
32 |
33 | //actions |
34 | addAction(new Age()); |
35 | addAction(new DeathLife()); |
36 | addAction(new Move()); |
37 | addAction(new ScaleCurve(0, 10)); |
38 |
39 | //gravity |
40 | var field:Field = new UniformField(0, 0.5); |
41 | var gravity:Gravity = new Gravity(); |
42 | gravity.addField(field); |
43 | addAction(gravity); |
44 | } |
45 | } |
46 | } |
Now you have created an effect with particles shooting out from the center of the stage, being pulled down by gravity. This is what it looks like: Milestone View It Online
Step 3: Floor Effect Add the Deflector
Add the folloing code in the emitter constructor. It creates a line deflector, adds it to the Deflector action, and then adds the action to the emitter, thus activating the deflector effect. The first two constructor paramters for the LineDeflector class is the coordinate of a point on the line, and the last two parameters are the x- and y-components of the line’s normal vector. The Deflector.bounce property determines the “bounciness” of the line, 1 causing complete rebound, and 0 meaning no rebound at all. view source
print?
1 | //create a line deflector passing through point (320, 320) and normal (0, -1) |
2 | var deflector:Deflector = new LineDeflector(320, 320, 0, -1); |
3 | deflector.bounce = 0.6; |
4 | var deflect:Deflect = new Deflect(); |
5 | deflect.addDeflector(deflector); |
6 | addAction(deflect); |
You may also draw a visual representation of the line on the stage to have a better look. [You must be registered and logged in to see this image.]
Alright, we’re done with this example. Now let’s take a look of our final outcome. Milestone View It Online
Bounding Box
In this example, we’re going to use the BoundingBox deflector to constrain particles inside a rectangular area.
Step 1: Bounding Box The Emitter Class
The document class remains the same as the previous example, but we are going to change the emitter class. This is the base emitter class of this example. Compared to the emitter class in the previous example, the SteadClock is changed to a ImpulseClock to instantly create 20 particles at the beginning, the position zone is changed from a single point to a rectangular zone that matches the stage size, the Velocity initializer is slowed down a bit, the Life initializer is removed because we want particles to stay permanently on the stage, the Age and DeathLife actions are in turn not required and removed, and the ScaleCurve is also removed. Some imports are also added and removed; you may just copy the code below for convenience. view source
print?
01 | package { |
02 | import idv.cjcat.stardust.common.clocks.ImpulseClock; |
03 | import idv.cjcat.stardust.common.initializers.CollisionRadius; |
04 | import idv.cjcat.stardust.common.initializers.Scale; |
05 | import idv.cjcat.stardust.common.math.UniformRandom; |
06 | import idv.cjcat.stardust.twoD.actions.Deflect; |
07 | import idv.cjcat.stardust.twoD.actions.Move; |
08 | import idv.cjcat.stardust.twoD.deflectors.BoundingBox; |
09 | import idv.cjcat.stardust.twoD.deflectors.Deflector; |
10 | import idv.cjcat.stardust.twoD.emitters.Emitter2D; |
11 | import idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; |
12 | import idv.cjcat.stardust.twoD.initializers.Position; |
13 | import idv.cjcat.stardust.twoD.initializers.Velocity; |
14 | import idv.cjcat.stardust.twoD.zones.LazySectorZone; |
15 | import idv.cjcat.stardust.twoD.zones.RectZone; |
16 | import idv.cjcat.stardust.twoD.zones.SinglePoint; |
17 |
18 | public class CircleEmitter extends Emitter2D { |
19 |
20 | private var impulseClock:ImpulseClock; |
21 |
22 | public function CircleEmitter() { |
23 | super(impulseClock = new ImpulseClock(20)); |
24 | impulseClock.impulse(); |
25 |
26 | //initializers |
27 | addInitializer(new DisplayObjectClass(Circle)); |
28 | addInitializer(new Position(new RectZone(0, 0, 640, 400))); |
29 | addInitializer(new Velocity(new LazySectorZone(3, 2))); |
30 | addInitializer(new Scale(new UniformRandom(1, 0.4))); |
31 | addInitializer(new CollisionRadius(10)); |
32 |
33 | //actions |
34 | addAction(new Move()); |
35 | } |
36 | } |
37 | } |
Step 2: Bounding Box Add the Deflector
Pretty much like the previous example, we now add the following code in the emitter constructor to use the Deflect action, only that this time we use the BoundingBox deflector to constrain particles inside a rectangular region that matches the stage size.
google_protectAndRun("render_ads.js::google_render_ad", google_handleError, google_render_ad);
view source
print?
1 | //deflector |
2 | var deflector:Deflector = new BoundingBox(0, 0, 640, 400); |
3 | var deflect:Deflect = new Deflect(); |
4 | deflect.addDeflector(deflector); |
5 | addAction(deflect); |
Step 3: Bounding Box Test the Movie
That’s it. Nothing much is changed, and now we have constrained particles in a bounding box. Test the movie and you shall see the result. Milestone View It Online
Custom Deflectors
Now, we are going to create custom deflectors on our own. Let’s first understand the Deflector class we’re about to extend.
The Deflector class is the base class for all deflectors. In order to create custom deflectors, you should extend this class and override the calculateMotionData4D() method, and then return a MotionData4D object representing the 4D vector output of the deflector. The input at your disposal, just like the Field class, is included in the Particle2D object passed into the method as parameter. You may use this Particle2D object to determine your output. By the way, if this method returns a null value, the Deflect action would assume that you do not want to change the current particle’s motion, ignore the particle, and then go on to processing the next particle.
For instance, the following deflector would rotate each particle’s velocity vector by one degree clock-wise. view source
print?
01 | package { |
02 | import idv.cjcat.stardust.twoD.geom.Vec2D; |
03 | import idv.cjcat.stardust.twoD.particles.Particle2D; |
04 | import idv.cjcat.stardust.twoD.deflectors.Deflector; |
05 | import idv.cjcat.stardust.twoD.geom.MotionData4D; |
06 |
07 | public class Rotator extends Deflector { |
08 |
09 | override protected function calculateMotionData4D(particle:Particle2D):MotionData4D { |
10 | var velocity:Vec2D = new Vec2D(particle.vx, particle.vy); |
11 | velocity.rotateThis(1); |
12 | return new MotionData4D(particle.x, particle.y, velocity.x, velocity.y); |
13 | } |
14 | } |
15 | } |
Tube Deflector Effect
In this example, we are going to extend the Deflector class and create our own deflector, simulating a tube, which is essentially two line deflectors sandwiching a tube-shaped free space. [You must be registered and logged in to see this image.]
Step 1: Tube Deflector Effect The Emitter Class
Copy the Flash document, along with the Circle symbol, and the document from the first example. Here we are going to create another emitter class, still named CircleEmitter. This time the emitter emits particles from the center of the stage, and no gravity field is applied. view source
print?
01 | package { |
02 | import idv.cjcat.stardust.common.actions.Age; |
03 | import idv.cjcat.stardust.common.actions.DeathLife; |
04 | import idv.cjcat.stardust.common.actions.ScaleCurve; |
05 | import idv.cjcat.stardust.common.clocks.SteadyClock; |
06 | import idv.cjcat.stardust.common.initializers.CollisionRadius; |
07 | import idv.cjcat.stardust.common.initializers.Life; |
08 | import idv.cjcat.stardust.common.initializers.Scale; |
09 | import idv.cjcat.stardust.common.math.UniformRandom; |
10 | import idv.cjcat.stardust.twoD.actions.Deflect; |
11 | import idv.cjcat.stardust.twoD.actions.Move; |
12 | import idv.cjcat.stardust.twoD.deflectors.Deflector; |
13 | import idv.cjcat.stardust.twoD.emitters.Emitter2D; |
14 | import idv.cjcat.stardust.twoD.initializers.DisplayObjectClass; |
15 | import idv.cjcat.stardust.twoD.initializers.Position; |
16 | import idv.cjcat.stardust.twoD.initializers.Velocity; |
17 | import idv.cjcat.stardust.twoD.zones.LazySectorZone; |
18 | import idv.cjcat.stardust.twoD.zones.SinglePoint; |
19 |
20 | public class CircleEmitter extends Emitter2D { |
21 |
22 | public function CircleEmitter() { |
23 | super(new SteadyClock(1)); |
24 |
25 | //initializers |
26 | addInitializer(new DisplayObjectClass(Circle)); |
27 | addInitializer(new Life(new UniformRandom(60, 10))); |
28 | addInitializer(new Position(new SinglePoint(320, 200))); //stage center |
29 | addInitializer(new Velocity(new LazySectorZone(8, 4))); |
30 | addInitializer(new Scale(new UniformRandom(1, 0.4))); |
31 | addInitializer(new CollisionRadius(10)); |
32 |
33 | //actions |
34 | addAction(new Age()); |
35 | addAction(new DeathLife()); |
36 | addAction(new Move()); |
37 | addAction(new ScaleCurve(0, 10)); |
38 | } |
39 | } |
40 | } |
Step 2: Tube Deflector Effect The Tube Deflector
Now we are going to create our tube deflector class. Details are explained in comments. view source
print?
01 | package { |
02 | import idv.cjcat.stardust.twoD.particles.Particle2D; |
03 | import idv.cjcat.stardust.twoD.deflectors.Deflector; |
04 | import idv.cjcat.stardust.twoD.geom.MotionData4D; |
05 |
06 | public class TubeDeflector extends Deflector { |
07 |
08 | private var y1:Number; |
09 | private var y2:Number; |
10 |
11 | public function TubeDeflector(y1:Number, y2:Number) { |
12 | //y2 should be larger than y2 |
13 | if (y1 > y2) { |
14 | //swap y1 and y2 if y1 is larger |
15 | var temp:Number = y1; |
16 | y1 = y2; |
17 | y2 = temp; |
18 | } |
19 |
20 | this.y1 = y1; |
21 | this.y2 = y2; |
22 | } |
23 |
24 | override protected function calculateMotionData4D(particle:Particle2D):MotionData4D { |
25 | //output components, initialized to the particle's original motion data |
26 | var x:Number = particle.x; |
27 | var y:Number = particle.y; |
28 | var vx:Number = particle.vx; |
29 | var vy:Number = particle.vy; |
30 |
31 | //caluculate actual collsion radius |
32 | var radius:Number = particle.collisionRadius * particle.scale; |
33 |
34 | //flag for whether the deflector takes effect |
35 | var deflected:Boolean = false; |
36 |
37 | if (particle.y < (y1 + radius)) { |
38 | //particle y-coordinate is less than lower limit |
39 | //set proper new y-coordinate |
40 | y = y1 + radius; |
41 |
42 | //set flag |
43 | deflected = true; |
44 | } else if (particle.y > (y2 - radius)) { |
45 | //particle y-coordinate is greater than upper limit |
46 | //set proper new y-coordinate |
47 | y = y2 - radius; |
48 |
49 | //set flag |
50 | deflected = true; |
51 | } |
52 |
53 | if (deflected) { |
54 | return new MotionData4D(x, y, vx, vy); |
55 | } else { |
56 | //ignore the particle and not update its motion data |
57 | return null; |
58 | } |
59 | } |
60 | } |
61 | } |
Step 3: Tube Deflector Effect Add the Deflector
You should know what we’re going to do next very well by now. That’s right, we’re going to add the deflector to a Deflect action and then add the action to the emitter. Add the following code in the emitter constructor. view source
print?
1 | //create a tube deflector |
2 | var deflector:Deflector = new TubeDeflector(100, 300); |
3 | var deflect:Deflect = new Deflect(); |
4 | deflect.addDeflector(deflector); |
5 | addAction(deflect); |
Step 4: Tube Deflector Effect Test the Movie
You can now test the movie. Again, you may also draw some visual representation of the deflector on the stage for a better look. Milestone View It Online
Conclusion
This is the end of the entire tutorial. In the first part you have learned about gravitational fields. In the second part, you have learned the concept of deflectors and the actual usage of the Deflect action. Also, you’ve learned how to extend the Deflector class to create custom deflectors. Now you’re able to perform advanced particle motion manipulation in Stardust.
Thank you very much for reading!]