Perlin Particles within a Circular Boundary in AS3
The above example is another take on moving particles with perlinNoise. This time I'm containing the particles within a circular boundary by using the logic from my previous post, Mirrored Circular Motion in AS3, to regenerate particles on the opposite side of the circle. This experiment, as well as the rest of my perlin particle experiments, inspired by the magic Robert Hodgin created with his Weird Fishes video.
Note: The CPU performance improves a great deal when the PerlinNoise object is NOT added to the display list. For the sake of this example, I added to the display list to show how it effects the movement.
The class looks like:
package com { /** * Perlin Particles Within a Circular Boundary by Mike T. Henderson, * is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. * Based on a work at mikethenderson.com. */ import flash.display.Sprite; import flash.display.MovieClip; import flash.display.Bitmap; import flash.display.Stage; import flash.display.GradientType; import flash.geom.Point; import flash.display.BitmapData; import flash.events.Event; public class perlinParticleSphere extends Sprite { // stage and boundaries properties private var _centerX:int = 0; private var _centerY:int = 0; private var _radius:int = 100; // perlinNoise Properties private var _perlinW:int = 250; private var _perlinH:int = 250; private var _baseX:int = 100; private var _baseY:int = 100; private var _octaves:int = 1; private var _stitch:Boolean = true; private var _fractal:Boolean = true; private var _grayScale:Boolean = true; private var _channels:int = 1; private var _xWind:int = 1; private var _yWind:int = 1; private var seed:int = Math.floor( Math.random() * 100 ); // particle properties private var _tparticles:int = 500; private var speed:int = 2; private var dx:Number; private var dy:Number; private var dist:Number; private var oppRadians:Number; private var radians:Number; private var randomX:Number; private var randomY:Number; // private display objects private var Flock:MovieClip; private var myBD:BitmapData = new BitmapData( _perlinW, _perlinH ); // public display objects public var myPerlin:Bitmap = new Bitmap( myBD ); public var Bounds:Sprite; // pixel properties private var minColor:int = int( Number.MAX_VALUE ); private var maxColor:int = 0; private var pixelData:uint; // offset properties private var point1:Point = new Point( 0, 0 ); private var point2:Point = new Point( 0, 0 ); private var offset:Array = [ point1, point2 ]; /* ------------------------------------------------------------------------------------------------ // constructor --------------------------------------------------------------------------------------------- */ public function perlinParticleSphere() {} /* ------------------------------------------------------------------------------------------------ // setters --------------------------------------------------------------------------------------------- */ // stage and boundaries setters public function set centerX( v:int ):void { _centerX = v; } public function set centerY( v:int ):void { _centerY = v; } public function set radius( v:int ):void { _radius = v; } // perlinNoise setters public function set perlinW( v:int ):void { _perlinW = v; } public function set perlinH( v:int ):void { _perlinH = v; } public function set baseX( v:int ):void { _baseX = v; } public function set baseY( v:int ):void { _baseY = v; } public function set octaves( v:int ):void { _octaves = v; } public function set stitch( v:Boolean ):void { _stitch = v; } public function set fractal( v:Boolean ):void { _fractal = v; } public function set grayScale( v:Boolean ):void { _grayScale = v; } public function set channels( v:int ):void { _channels = v; } public function set xWind( v:int ):void { _xWind = v; } public function set yWind( v:int ):void { _yWind = v; } // particle setters public function set tparticles( v:int ):void { _tparticles = v; } /* ------------------------------------------------------------------------------------------------ // getters --------------------------------------------------------------------------------------------- */ // stage and boundaries getters public function get CenterX():int { return _centerX; } public function get CenterY():int { return _centerY; } public function get Radius():int { return _radius; } // perlinNoise getters public function get PerlinW():int { return _perlinW; } public function get PerlinH():int { return _perlinH; } public function get BaseX():int { return _baseX; } public function get BaseY():int { return _baseY; } public function get Octaves():int { return _octaves; } public function get Channels():int { return _channels; } public function get XWind():int { return _xWind; } public function get YWind():int { return _yWind; } // particle getters public function get TParticles():int { return _tparticles; } /* ------------------------------------------------------------------------------------------------ // init --------------------------------------------------------------------------------------------- */ public function init():void { // build perlin noise myPerlin.x = _centerX - ( myPerlin.width/2 ); myPerlin.y = _centerY - ( myPerlin.height/2 ); myPerlin.visible = false; addChild( myPerlin ); // add circle boundaries Bounds = new Sprite(); updateBounds(_radius); Bounds.x = _centerX; Bounds.y = _centerY; addChild( Bounds ); // add Flock container Flock = new MovieClip(); addChild( Flock ); // add the particles updateFlock(); // add enterFrame Flock.addEventListener( Event.ENTER_FRAME, updateParticle ); } /* ------------------------------------------------------------------------------------------------ // update Flock --------------------------------------------------------------------------------------------- */ public function updateFlock():void { if ( _tparticles > Flock.numChildren ) { while ( Flock.numChildren < _tparticles ) { // build particle var myParticle:MovieClip = new MovieClip(); myParticle.graphics.lineStyle( 3, 0, 1); myParticle.graphics.moveTo(0, 0); myParticle.graphics.lineTo(1, 1); dx = Math.random() * _radius; dy = Math.random() * _radius; radians = Math.atan2( dy, dx ); randomX = Math.cos( radians ) * dx; randomY = Math.sin( radians ) * dy; myParticle.x = _centerX + ( Math.sin( Math.random() * randomX ) * randomX ); myParticle.y = _centerY + ( Math.sin( Math.random() * randomY ) * randomY ); // add random speeds myParticle.xspeed = Math.sin( Math.random() * speed ) * speed; myParticle.yspeed = Math.sin( Math.random() * speed ) * speed; Flock.addChild( myParticle ); } } else { while ( Flock.numChildren > _tparticles ) { Flock.removeChildAt( _tparticles ); } } } /* ------------------------------------------------------------------------------------------------ // update Particle --------------------------------------------------------------------------------------------- */ private function updateParticle( e:Event ):void { var i:int = 0; var myParticle:MovieClip; updateNoise(); while ( i < Flock.numChildren) { myParticle = Flock.getChildAt( i ) as MovieClip; // find pixel color under Particle var curColor:uint = myBD.getPixel( int(myParticle.x - (_centerX - _radius)), int(myParticle.y - (_centerY - _radius)) ); // find rotation by taking the difference of current color - minColor and the maxColor var pixPerc:Number = Number((curColor - minColor) / maxColor); // update properties myParticle.x += ( myParticle.xspeed * Math.cos(pixPerc * (Math.PI * 2))); myParticle.y += ( myParticle.yspeed * Math.sin(pixPerc * (Math.PI * 2))); myParticle.scaleX = pixPerc; myParticle.scaleY = pixPerc; // find the distance dx = myParticle.x - _centerX; dy = myParticle.y - _centerY; dist = Math.sqrt( dx * dx + dy * dy ); if ( dist >= _radius + 2 ) { // find opposite location oppRadians = Math.atan2( -dy, -dx ); // send it to the other side myParticle.x = _centerX + Math.cos( oppRadians ) * _radius; myParticle.y = _centerY + Math.sin( oppRadians ) * _radius; // create new random speed using sine wave myParticle.xspeed = Math.sin( Math.random() * speed ) * speed; myParticle.yspeed = Math.sin( Math.random() * speed ) * speed; } i++; } } /* ------------------------------------------------------------------------------------------------ // Perlin methods --------------------------------------------------------------------------------------------- */ private function updateNoise() { offset[0].x += int( _xWind ); offset[0].y += int( _yWind ); myBD.perlinNoise( _baseX, _baseY, _octaves, seed, _stitch, _fractal, _channels, _grayScale, offset ); updateMinMaxPixel(); } private function updateMinMaxPixel():void { for (var x:int = 0; x < _perlinW; x++) { for (var y:int = 0; y < _perlinH; y++) { pixelData = uint( myBD.getPixel(x, y) ); minColor = int( Math.min(pixelData, minColor) ); maxColor = int( Math.max(pixelData, maxColor) ); } } } /* ------------------------------------------------------------------------------------------------ // Update bounds --------------------------------------------------------------------------------------------- */ public function updateBounds( r:int ):void { _radius = r; Bounds.graphics.clear(); Bounds.graphics.lineStyle( 1, 0xcccccc, 1 ); Bounds.graphics.beginGradientFill( GradientType.RADIAL, [0xffffff, 0xcccccc], [.35,.35], [0,255]); Bounds.graphics.drawCircle( 0, 0, _radius ); } } }
Then to call it:
import com.perlinParticleSphere; var mySphere:perlinParticleSphere = new perlinParticleSphere(); mySphere.centerX = 125; mySphere.centerY = 295; mySphere.init(); addChild( mySphere );

Perlin Particles Within a Circular Boundary by Mike T. Henderson
is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.
Based on a work at mikethenderson.com.

No Comments »
No comments yet.
RSS feed for comments on this post. TrackBack URI
Leave a comment