Flint Particle System Forum - Liquid Interactions Thu, 23 Jun 2011 13:21:43 +0100 http://flintparticles.org/forum/ Lussumo Vanilla 1.1.10 & Feed Publisher Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=162#Comment_162 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=162#Comment_162 Sat, 24 May 2008 04:28:38 +0100 Draco18s
I started with the Flocking.as script and started adding things and removing things to try and get a somewhat liquid-like behavior out of the particles. For the most part I've succeeded, however, now I want to add more complex behavior.

What I'm trying to accomplish is use the system to try and avoid writing my own particle system to appoximate flowing lava while the user commands a water cannon (it's a game). I need to be able to effect the particles (make them stop moving and change color to black, and at some point they should be able to revert) as well as get the rest of the particles to flow around the "frozen" ones. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=164#Comment_164 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=164#Comment_164 Sat, 24 May 2008 09:57:15 +0100 Richard
My immediate thoughts are...

You can stop a particle by changing its velX and velY properties to zero. You can change its color to black by setting its color property to zero (or 0x000000 which is the same thing). You could also store the previous values in the particle's dictionary for retrieval later. Where you place this code depends on what causes the particle to stop. To integrate it with the rest of the system you probably want to create a custom action. This might look something like this...

package
{
import org.flintparticles.actions.Action;
import org.flintparticles.emitters.Emitter;
import org.flintparticles.particles.Particle;

public class CustomStopStart extends Action
{
private function shouldStop( particle:Particle ):Boolean
{
// do calculations and return a boolean to indicate if the particle should be stopped or moving
}

override public function update( emitter:Emitter, particle:Particle, time:Number ):void
{
if ( shouldStop( particle ) )
{
if( !particle.dictionary[this] )
{
var oldValues:Object = { velX:particle.velX, velY:particle.velY, color:particle.color };
particle.dictionary[this] = oldValues;
particle.velX = 0;
particle.velY = 0;
particle.color = 0;
}
}
else
{
if( particle.dictionary[this] )
{
var oldValues:Object = particle.dictionary[this];
particle.velX = oldValues.velX;
particle.velY = oldValues.velY;
particle.color = oldValues.color;
particle.dictionary[this] = null;
}
}
}
}
}


Use the action object itself as the key in the dictionary so you don't clash with any other actions that use the dictionary.

The shouldStop method does whatever it needs to do to determine if the particle should be stationary or not.

What remains (other than deciding what goes in the shouldStop method) is to make the moving particles flow around the stationary ones. You may be able to do this with the minimumDistance action, although I suspect you might get a logjam of particles stopping in front of the stationary particles. Adding a TargetVelocity may fix this - it will cause the particles to try not to stop, but you need to try it to find the consequences of this mix, and it may mess with your other actions. If it doesn't work, you need an avoidance action, which requires particles to steer around other particles. That's not so easy but their are some resources on steering behaviour online - your favourite search engine is a good place to start.

Good luck and let us know how you get on. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=165#Comment_165 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=165#Comment_165 Sat, 24 May 2008 17:44:13 +0100 Draco18s I'm new to AS3 (had to grab Flash CS3 just to use the great system you guys built) and was more or less at a loss on how to make it do New Stuff. ]]> Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=166#Comment_166 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=166#Comment_166 Sun, 25 May 2008 04:23:26 +0100 Draco18s
Looks like Age might be able to do the duration, but I need to be able to check for the mouse event.

Thanks again. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=167#Comment_167 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=167#Comment_167 Mon, 26 May 2008 08:09:39 +0100 Draco18s However, if I make a constructor function and create the variable there, the compiler complains about undefined properties. ]]> Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=168#Comment_168 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=168#Comment_168 Mon, 26 May 2008 18:10:03 +0100 Richard
To avoid the duplicate definition of oldValues, try this.

package
{
import org.flintparticles.actions.Action;
import org.flintparticles.emitters.Emitter;
import org.flintparticles.particles.Particle;

public class CustomStopStart extends Action
{
private function shouldStop( particle:Particle ):Boolean
{
// do calculations and return a boolean to indicate if the particle should be stopped or moving
}

override public function update( emitter:Emitter, particle:Particle, time:Number ):void
{
var oldValues:Object;
if ( shouldStop( particle ) )
{
if( !particle.dictionary[this] )
{
oldValues = { velX:particle.velX, velY:particle.velY, color:particle.color };
particle.dictionary[this] = oldValues;
particle.velX = 0;
particle.velY = 0;
particle.color = 0;
}
}
else
{
if( particle.dictionary[this] )
{
oldValues = particle.dictionary[this];
particle.velX = oldValues.velX;
particle.velY = oldValues.velY;
particle.color = oldValues.color;
particle.dictionary[this] = null;
}
}
}
}
}
]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=171#Comment_171 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=171#Comment_171 Tue, 27 May 2008 00:48:21 +0100 Draco18s
By "disapears" I mean that if I do anything that could result in shouldStop() in returning true (such as an if(Math.random() < 0.01) { return true; } else {return false;} ) then no particles are rendered, at all, ever.

slowing the movie down to 1 FPS I did see them flash briefly at 0,0. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=172#Comment_172 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=172#Comment_172 Tue, 27 May 2008 01:07:50 +0100 Draco18s
I got them to not all disapear at once. However, when the shouldStop() does return true, the particle simply pops (flashes briefly at 0,0 and then is gone). Had to declare oldValues as a class variable, not a function variable. Thought something was wrong.

But still, what causes _x and _y (as per movieClip) to become undefined? ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=173#Comment_173 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=173#Comment_173 Tue, 27 May 2008 05:26:09 +0100 Draco18s
On another note, I was looking at the possibility of adding and removing actions from the list for these stopped particles, but that doesn't look feasible (things go nuts), not that the removeAction function seems to work. I can't find any examples of how to call it, and the only way I've gotten it to compile it hasn't worked anyway. The idea was to remove the minimumDistance that the moving ones have (a pretty soft one, distance 30, acceleration 30) and make it a bit firmer, to prevent the moving particles from passing throught the stopped ones (distance 30, acceleration 100).

Anyway, here's what I've done, if it makes more sense that way, assuming I'm using the right tags. ^^;


package org.flintparticles.actions
{
import org.flintparticles.actions.Action;
import org.flintparticles.emitters.Emitter;
import org.flintparticles.particles.Particle;

public class CustomStopStart extends Action
{
//I also added these to the particle.as script, having them
//here didn't seem to let things work right
//it would use the same variable for ALL the particles instead
//of on a one-by-one basis
public var Stopped:Boolean;
public var oldValues:Object;
public var oldVelX:Number = 0;
public var oldVelY:Number = 0;
//end particle.as mod

private function shouldStop( particle:Particle ):Number
{
//at the moment, a RNG determines state--was the first
//thing I got to make all the particles different
if(particle.Stopped) {
if(Math.random() < 0.001) {
//trace("stopping");
return 1;
}
//trace("still stopped");
return -2;
}
else{
if(Math.random()< 0.001) {
//trace("starting");
return -1;
}
//trace("still moving");
return 2;
}
return 0;
}

override public function update( emitter:Emitter, particle:Particle, time:Number ):void
{
var s = shouldStop( particle );
if (s < 0 )
{
if( s == -1)
{
particle.oldValues = particle.dictionary[this];
particle.oldVelX = particle.velX;
particle.oldVelY = particle.velY;
particle.scale = 0.5;
particle.velX = .0000000001;
particle.velY = .0000000001;
particle.color = 0xFF000000;
particle.dictionary[this] = null;
particle.Stopped = true;
}
else {
particle.velX = -particle.velX;
particle.velY = -particle.velY;
}
}
else
{
if( s == 1 )
{
particle.dictionary[this] = oldValues;
particle.scale = 1;
particle.color = 0xFFFFFFFF;
particle.Stopped = false;
}
}
}
}
}
]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=174#Comment_174 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=174#Comment_174 Tue, 27 May 2008 08:04:00 +0100 Richard
package org.flintparticles.actions
{
import org.flintparticles.actions.Action;
import org.flintparticles.emitters.Emitter;
import org.flintparticles.particles.Particle;

public class CustomStopStart extends Action
{
private function shouldStop( particle : Particle ) : Boolean
{
if( particle.dictionary[this] ) // particle is stopped
{
return Math.random() < 0.95;
}
else // particle is not stopped
{
return Math.random() < 0.05;
}
}

override public function update( emitter : Emitter, particle : Particle, time : Number ) : void
{
var oldValues : Object;
if ( shouldStop( particle ) )
{
if( !particle.dictionary[this] )
{
oldValues = { velX:particle.velX, velY:particle.velY, color:particle.color };
particle.dictionary[this] = oldValues;
particle.velX = 0;
particle.velY = 0;
particle.color = 0;
}
}
else
{
if( particle.dictionary[this] )
{
oldValues = particle.dictionary[this];
particle.velX = oldValues.velX;
particle.velY = oldValues.velY;
particle.color = oldValues.color;
particle.dictionary[this] = null;
}
}
}
}
}


Things to be aware of -

  • If you set the velocity to zero (particle.velX = 0, particle.velY = 0) in this action, other actions may change it again or may react to it. So if you are getting strange behaviours look for other actions that are dependent on the properties you're setting here. For example, if you have a minimumDistance action on the particles, this will cause the particles to accelerate away from other particles, which means particles will start moving again after you set the velocity to zero.

  • The particle class is not dynamic. Trying to add random properties to it (e.g. particle.stopped) is likely to cause errors.

  • But the particle has a dictionary that you can add properties to (hence reading and writing to particle.dictionary[this]).

  • By setting the dictionary entry for this class to null when the particle is not stopped, we can tell if the particle is stopped just by testing whether this property is set [if( particle.dictionary[this] )]

  • Actions are not set on particles, they are set on the emitter and apply to all particles created by that emitter. So removeAction is a method of the emitter, not the particle.

  • One instance of the action class is used by all particles so any state held in this instance is shared by all the particles. Particle specific state must be stored in the particle dictionary.

]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=177#Comment_177 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=177#Comment_177 Fri, 30 May 2008 21:30:04 +0100 Draco18s I'm not sure *why* it pops the particle when certain attributes are set to 0 (didn't really look into it), but that's what was doing it.

Anyway, new question:

Is it possible to use a constant stream emission of particles, yet have a cap on the number of existant particles? emitter.pause() pauses the whole thing, what I need is just a pause on the creation of new particles so I don't ever have more than about 3 or 4 hundred on the screen at once.

Thanks. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=179#Comment_179 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=179#Comment_179 Sun, 01 Jun 2008 22:04:31 +0100 Draco18s Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=180#Comment_180 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=180#Comment_180 Mon, 02 Jun 2008 13:42:09 +0100 ericr Why can't it make sense?
Give it time - it will. An absolutely indispensable resource for AS3 programming is Collin Moock's "Essential ActionScript 3.0": a fantastic resource for even the most seasoned programmer.

_root *should always be available!*
_root is a deprecated AS2 convention. In AS3, _root is known as the stage and you always have access to it. All display objects that are in the Display List (including your "Main" class which has to extend Sprite or MovieClip) have a reference to the Stage.

Let's say you're in your Main class or equivalent (or the Action panel) and you need to access the Stage. It's as simple as this:
trace(this.stage.stageWidth);
That will trace the width of your Stage. It's pretty darn simple and convenient once you get the hang of things! ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=181#Comment_181 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=181#Comment_181 Mon, 02 Jun 2008 20:48:36 +0100 Draco18s
BTW, my question about stopping particle emission is still relevant. Still curious on how to do that. Almost had what I wanted at one point by flipping the emitter.counter variable, though I had a limit to how well the comparison opperator worked (had to cast it as a string, rather than being able to directly compare one object to another, so I couldn't change it from one kind of steady to another; had to flop between a blast (zero emission) and a steady (normal emission)). I was wondering if there was a better way. The...performance adjusted counter didn't quite do what I wanted. It seemed to slow down and then no speed back up again, as if it found an emission rate that it would be able to keep up forever regardless of what I did to prevent or encourage particle death. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=185#Comment_185 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=185#Comment_185 Thu, 05 Jun 2008 07:57:28 +0100 Richard
So, for example...

emitter.counter = new Steady( 100 );

// stop the counter

emitter.counter.stop();

// restart the counter

emitter.counter.resume();

// adjust the rate of the counter

emitter.counter.rate = 50;
]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=187#Comment_187 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=187#Comment_187 Thu, 05 Jun 2008 08:34:19 +0100 Draco18s
Anyway, all that's left is to figure out why the mouse event listener I set up this afternoon* isn't working (despite being coded exactly how the documentation coded it, sole exception being that the stage was passed to the package instead of being called using 'stage'). That one I'll hit the Adobe forums for.

You guys have been great. :)

*I have a "water cannon" at the bottom of the screen shooting blue particles (Sparkler example modified) towards the mouse (not the best solution to use TurnTowardsMouse, but the easiest) that upon 'contact' with the magma, hardens it (script as above, only instead of distance to the mouse, distace to each particle in the water spray--probably not the fastest meathod, but an easy solution). ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=188#Comment_188 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=188#Comment_188 Thu, 05 Jun 2008 10:35:13 +0100 Richard Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=191#Comment_191 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=191#Comment_191 Thu, 05 Jun 2008 20:59:53 +0100 Draco18s And I did check that they're in the Steady.as file, this is weird.

Meh, I'll go back to the setting it to Blast and then back to Steady, it works as long as I make sure it's only being called once when it needs to change. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=193#Comment_193 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=193#Comment_193 Fri, 06 Jun 2008 07:44:58 +0100 Richard
Steady( emitter.counter ).stop();

or store the counter in a variable of type Steady...

var steadyCounter:Steady = new Steady( 100 );
emitter.counter = steadyCounter;
steadyCounter.stop();
]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=196#Comment_196 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=196#Comment_196 Sat, 07 Jun 2008 15:21:34 +0100 Draco18s
Anyway, I've tossed up the swf here: http://www.pages.drexel.edu/~mmj29/temp/Magma.swf

I think there are about 4 custom .as files extending action in that. Oh, and emitter.dispose() doesn't actually clean up the particles because the ParticleFactory code contains three empty functions. Didn't find a quick work-around. Also never figured out how to use the particle dictionary, mostly because what I had worked and I was running out of time (there's still some temporary graphics because a group member didn't give me any actual graphics). ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=200#Comment_200 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=200#Comment_200 Mon, 09 Jun 2008 08:12:42 +0100 Richard emitter.dispose() doesn't actually clean up the particles because the ParticleFactory code contains three empty functions

ParticleFactory is an interface - interfaces contain method signatures without implementations. The implementation being used is in ParticleCreator. There is a different reason for dispose not working (it wasn't telling the renderer to remove the particles) - I've checked a fix into SVN. ]]>
Liquid Interactions http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=202#Comment_202 http://flintparticles.org/forum/comments.php?DiscussionID=34&Focus=202#Comment_202 Mon, 09 Jun 2008 13:02:35 +0100 ericr Well, I finished up last night and spent an hour and a half making buttons (three to be precise) and decided that AS3's way of doing buttons is not better than AS2's, because of the variables needed by the button (the particle emitters can't be started until the Play button is clicked, which means the code needs to be inside one of the particle package scripts that has access to the stage, which means that the Play button MUST be somewhere on the screen on the first frame of the movie...meaning that my group member's nice pre-game animation has to play behind the buttons.

I'm not 100% sure what your build process and development setup is but you should be importing the Flint packages you need into your project (whether that's in the Actions panel in CS3 or your Main class in Flex/Flash Develop/Other). Either way you do it you can hide the buttons (even if this means making them transparent) if you feel they need to be on the Stage from the get-go...

If you're serious about Flash development then I'd seriously take a look at Essential Actionscript 3.0. That book is the first place I go whenever any AS3 confusions arises and it's saved my butt time and again. :) ]]>