theboywhocriedWoolf | Tal Woolf

NodeGarden and Particle Wall

0

Fun with Particles for all the ages

Since I first read Kieth Peters  “Foundation ActionScript Animation”, a book I strongly suggest you read,  I have wanted to make a Particle NodeGarden. So one Sunday afternoon I decide to treat myself and do that very thing.

The Garden in all its Splendour

The NodeGarden itself is pretty simple with each frame animating the Particles based on their acceleration, velocity, mass and interaction with each other. At the heart of it there are two main methods that are responsible for animating the particles. They can be switched at runtime in order to change the way that the particles interact with each other and therefore move.

On each EnterFrame a nested For loop that cycles through a vector of Particles, the first loop extracting the current element in the Vector and the second extracting the current element plus one. Thereby enabling each particle to be tested against the others in the Vector as they are passed onto the methods responsible for animating them.


var i : uint;
var j : uint;

var particleA : Particle;
var particleB : Particle;

for(  i = 0;  i < ( _particleVect.length - 1 );  i++ )
{
          particleA = _particleVect[  i  ];
          for(  j = i + 1; j < _particleVect.length;  j++ )
          {
                    particleB = _particleVect[ j ];
                    _animateFunction( particleA, particleB );
          }
}

The first animate method SpringParticles is pretty straightforward:

/*
* spring gravitation,
* spring to particle and increase strength using mass
*/
private function springParticles( particleA : Particle, particleB : Particle ) : void
{
          var dx : Number = particleB.x - particleA.x;
          var dy : Number = particleB.y - particleA.y;
          var distance : Number = Math.sqrt( dx * dx + dy * dy );

          if( distance < minDistance )
          {
                 var distAmount : Number = ( distance / minDistance );
                 // calculate amount being taken off

                 var colour : int = getColour( particleA.colour, particleB.colour );
                 particleA.tint( colour, _tintAmount - ( distAmount * _tintAmount ) );
                 particleB.tint( colour, _tintAmount - ( distAmount * _tintAmount ) );

                 _view.graphics.lineStyle( 2 - distAmount, colour, 1 - distAmount );
                 _view.graphics.moveTo(particleA.x, particleA.y);
                 _view.graphics.lineTo( particleB.x, particleB.y );
                  // apply forces
                 var ax : Number = dx * _springAmount;
                 var ay : Number = dx * _springAmount;
                 particleA.vx += ax / particleA.mass;
                 particleA.vy += ay / particleA.mass;
                 particleB.vx -= ax / particleB.mass;
                 particleB.vy -= ay / particleB.mass;
          }
}

As you can see this method firstly calculates the distance between both Particles using Pythagorus Theorem. If the distance is smaller than the minimum distance set, it then applies the appropriate forces to both particles.

First the acceleration is calculated for each axis using simple spring physics, getting the distance times by the spring amount. Next the acceleration is divided by the particles mass and applied or subtracted to each particles velocity.

If you look closely you can see that ParticleA has the acceleration added to its velocity as ParticleB has it subtracted, this effect pulls the particle towards each other.

The second animate method GravitatePartiles applies different forces to both particles to simulate a gravity effect:


/*
* gravitate function
* instead of springing and compare mass to add to force
*/
private function gravitateParticles( particleA : Particle, particleB : Particle ) : void
{
          var dx:Number = particleB.x - particleA.x;
          var dy:Number = particleB.y - particleA.y;
          var distSQ:Number = dx*dx + dy*dy;
          var distance:Number = Math.sqrt(distSQ);

          if( distance < minDistance )
          {
                    var distAmount : Number = ( distance / minDistance );
                    var colour : int = getColour( particleA.colour, particleB.colour );
                    particleA.tint( colour, _tintAmount - ( distAmount * _tintAmount ) );
                    particleB.tint( colour, _tintAmount - ( distAmount * _tintAmount ) );

                    _view.graphics.lineStyle( 2 - distAmount, colour, 1 - distAmount );
                    _view.graphics.moveTo( particleA.x, particleA.y );
                    _view.graphics.lineTo( particleB.x, particleB.y );

                    var force:Number = particleA.mass * particleB.mass / distSQ;
                    var ax:Number = force * dx / distance;
                    var ay:Number = force * dy / distance;

                    particleA.vx += ax / particleA.mass;
                    particleA.vy += ay / particleA.mass;
                    particleB.vx -= ax / particleB.mass;
                    particleB.vy -= ay / particleB.mass;
          }
          checkCollision( particleA, particleB );
}

The main difference between the two methods is how they calculate and apply the acceleration. GravitatePartiles brings an additional mechanism into play, Force.

The calculation for Gravity is: Force = Gravity * Mass1 * Mass2 / distance 2

By removing the need to have the precise gravitational amount as mentioned in “Foundation ActionScript Animation”, instead just calculate the gravity between both Particles, we can remove Gravity from the equation, which leaves us with the remaining calculation for Force. We then, just as before, apply or subtract the acceleration divided by mass to the velocity of each Particle.

Not Everything is so Black and White

I wanted to spice things up a little, so I added a few colour methods to alter the Particles’ colour during their interactions with each other.

The first method takes both Particles’ colours and returns the strongest colour (the one closest to white), with the resulting effect being that both Particles take on this colour. The second method colours the Particles based on a combination of both of their original colours. The third method removes all colour options and leaves both Particles at their original colours

Particle Wall

The Particle Wall is a wall of particles that when within a minimum distance from the mouse, spring away from it, returning to their original state when not.

You can achieve some really fun and interesting effects this way. Just start off with one Particle, adjusting its movement from the mouse, and then just add more particles.  Steven Burges illustrates this nicely with his ColourWall example.

The following method controls the movement for each particle:

/*
* displace particles and move away from the mouse
* based on mass
*/
private function avoidPosition( particle : Particle ) : void
{
          var originalPos : Point =  particle.startingPosition;
          var dx : Number = originalPos.x - mouseX; // distance from original position
          var dy : Number = originalPos.y - mouseY;
          var distance : Number = Math.sqrt( dx * dx + dy * dy );
          var targetPos : Point = new Point();
          var angle : Number = Math.atan2( dy, dx );

          if( distance < minDistance )
          {
                    targetPos.x = originalPos.x + Math.cos( angle ) * mouseMass; // get cords based on angel * mass
                    targetPos.y = originalPos.y + Math.sin( angle ) * mouseMass;
          }
          else
          {
                   targetPos.x = originalPos.x; // if not near minimum position, move back to starting position
                   targetPos.y = originalPos.y;
          }

          // stop movement if position is at resting point ( original position )
          if( particle.x === targetPos.x && particle.y === targetPos.y ) return;
          // move velocity to spring
          particle.vx = ( targetPos.x - particle.x ) * _springAmount;
          particle.vy = ( targetPos.y - particle.y ) * _springAmount;
          particle.vx *= _friction; particle.vy *= _friction;
          particle.x += particle.vx; particle.y += particle.vy;
}

At first the Particles distance from the Mouse is calculated, if below the minimum distance, set the new target point based on the Particles angle timed by the Mouse mass.

If below further than the minimum distance, set the target position to the Particles original position. Then simple spring the particle to the target position and apply friction to reduce its velocity.

Particles are fun to play with and despite all the Particle Systems already out there, which provide efficient particle effects, sometimes its nice to get down and dirty and just do it yourself.  So go and play around if you have the time.

View the NodeGarden or Spoon me on GitHub.

Leave a Reply

(* Required)