Constellation – A flocking experiment

This week I saw Flight 404’s “Swarm Behavior” on vimeo –

Swarm behavior from flight404 on Vimeo.

Yet another awesome video from Robert, using his Cinder framework. Cool!
In the description, he mentions the particle’s behavioral rules –

1) If I am far away from my neighbors, move towards them.
2) If I am too close to my neighbors, move away from them.
3) If I am neither too close or too far from my neighbors, move with them.

So I decided to try and implement these rules in Flash. The idea changed a few times, and ended up looking like an interactive constellation app. So here it is! It’s still pretty rough around the edges – but I’m quite pleased with how it’s developing.

See and edit the code over on Wonderfl

CODE

package{

	[SWF(width="465", height="465", frameRate="50")]

	import flash.events.*;
	import flash.events.KeyboardEvent;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.geom.Point;
	import flash.filters.BlurFilter;
	import flash.filters.ColorMatrixFilter;
	import flash.filters.ConvolutionFilter;
	import flash.filters.GlowFilter
	import flash.text.TextField;
	import com.bit101.components.*;
	
 	public class BFCWonderfl extends MovieClip {
		
		//Vars - 
		//You can play with these ones - 
		private var numBoids:int=20;
		//Boids closer than this will feel crowded!
		private var minDist:int=90;
		//Boid further away than another than this will be lonely!
		private var maxDist:int=100;
		//This is how fast the boids can move. TOP SPEED!
		private var maxSpeed:Number = 3;
		//This is how much boids influence each other - lower number = more influence
		private var divideBy:int=100;
		//Shall the boids slow down with friction?
		private var enableFriction:Boolean = true;
		private var friction:Number = 0.9;
		//Settle down - if they're not too close and not too far away from their friends - they'll just stop
		private var settleDown:Boolean = false;
		
		private var boidColour:uint = 0xffffff;
		private var lineColour:uint = 0xffffff;
		private var bgColour:uint   = 0x000033;
		
		private var glow:GlowFilter = new GlowFilter();
		private var glowColour:uint = 0x99ffff;

		//But you should probably leave these as is - 
		private var boidArray:Array=[];
		private var menuHeight:Number = 85;
		private var doMidi:Boolean = false;
		private var BMD:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight-menuHeight, false, bgColour);
		private var BF:BlurFilter = new BlurFilter(5,5,1);
		private var Bit:Bitmap = new Bitmap(BMD);
		private var bitHolder:MovieClip = new MovieClip;
		private var ballHolder:MovieClip = new MovieClip;
		private var isMouseDown:Boolean = false;
		private var TB:TextField = new TextField();
		private var myCheckBox1:CheckBox;
		private var myCheckBox2:CheckBox;
		private var mySlider1:HSlider;
		private var mySlider2:HSlider;
		//Boid Flock Class
		public function BFCWonderfl():void{
			trace("Init!");
			addChild(bitHolder);
			bitHolder.addChild(Bit);
			addChild(ballHolder);
			
			glow.color = glowColour;
			glow.alpha = .5;
			glow.blurX = 5;
			glow.blurY = 5;
			
			ballHolder.filters = [glow];
			
			addChild(TB);
			TB.y = 0;
			TB.width = stage.stageWidth-10;
			TB.height = 75;
			TB.selectable = false;
			TB.text = "Constellation by Lawrie\nhttp://www.LawrieCape.co.uk\nSpace to add a boid at mouse - click to attract - any other key to reset.\n\nADD MINIMAL COMPS HERE - MIN MAX sliders and Friction Settle checkboxes";
			
			myCheckBox1 = new CheckBox(this,5,50,"Friction?",updateVals);
			myCheckBox1.selected = true;
			myCheckBox2 = new CheckBox(this,5,70,"Settle?",updateVals);
			var sLabel:Label  = new Label(this,75,45,"Min size");
			var sLabel2:Label = new Label(this,75,65,"Max size");
				
			mySlider1 = new HSlider(this,125,50,updateVals);
			mySlider2 = new HSlider(this,125,70,updateVals);
			
			mySlider1.setSliderParams(1,200,75);
			mySlider2.setSliderParams(1,200,100);
			
			addChild(myCheckBox1);
			addChild(myCheckBox2);
			
			addChild(mySlider1);
			addChild(mySlider2);	
			
			bitHolder.y = menuHeight;
			ballHolder.y = menuHeight;
			ballHolder.mouseEnabled  = false;
			ballHolder.mouseChildren = false;
			bitHolder.alpha=1;
			
			BMD.fillRect(BMD.rect, bgColour);

			bitHolder.addEventListener(MouseEvent.MOUSE_DOWN, mouseIsDown);
			bitHolder.addEventListener(MouseEvent.MOUSE_UP,   mouseIsNotDown);			
			stage.addEventListener(KeyboardEvent.KEY_UP, makeASingleBoid);

			addEventListener(Event.ENTER_FRAME, updateBoids);
			//makeBoids(numBoids);
		}
		
		private function makeASingleBoid(e:KeyboardEvent):void{
			if(e.keyCode==32){
				makeBoids(1,mouseX,mouseY);
			}
			else{
				reset();
			}
		}
		
		private function mouseIsDown(e:Event):void{
			isMouseDown = true;
		}
		private function mouseIsNotDown(e:Event):void{
			isMouseDown = false;
		}
		
		private function makeBoids(makeXBoids:int, bX:Number = 0, bY:Number = 0):void {
			for (var i:int=0; imaxDist) {
					B.speedX-=B.distToB2X/divideBy;
					B.speedY-=B.distToB2Y/divideBy;
				}
				//2) If I am too close to my neighbors, move away from them.
				else if (B.distToB2stage.stageWidth){
					B.x=stage.stageWidth-B.speedX;
					B.speedX*=-friction;
				}
				else if(B.x<0){
					B.x=-B.speedX;
					B.speedX*=-friction;
				}
				if (B.y>(stage.stageHeight-menuHeight)){
					B.y=(stage.stageHeight-menuHeight)-B.speedY;
					B.speedY*=-friction;
				}
				else if(B.y<0){
					B.y=-B.speedY;
					B.speedY*=-friction;
				}
				
				//Limit them to a top speed - 
				if(B.speedX>maxSpeed){
					B.speedX = maxSpeed;
				}
				else if(B.speedX< -maxSpeed){
					B.speedX=-maxSpeed;
				}
				if(B.speedY>maxSpeed){
					B.speedY = maxSpeed;
				}
				else if(B.speedY< -maxSpeed){
					B.speedY=-maxSpeed;
				}		
				
				//Add friction?
				if(enableFriction){
					B.speedX*=friction;
					B.speedY*=friction;		
				}
				
				//Move them 
				B.x+=B.speedX;
				B.y+=B.speedY;
			
			}
			//Draw into the BMD

			BMD.draw(ballHolder);
			//Apply a blur?
			BMD.applyFilter(BMD,BMD.rect,new Point(0,0),BF);
		}
		
		private function reset():void{
			removeEventListener(Event.ENTER_FRAME, updateBoids);
			for (var i:int=0; i

Flash Midi Server 0.1 released + Sonar source code and audio air apps.

The title says it all really. I’ve updated the project page, but I’ll add the info here too incase you’re reading this through an RSS reader.

Flash Midi Server v0.1

Lawrie Cape 2010
Download from the Google Projects Page.

WHAT IS IT?

Flash Midi Server is method for sending MIDI data out of Flash. Using an Actionscript 3 class and a Processing application, you can create generative,

dynamic, fun audio tools in Flash.

WHY?

Mainly just for fun. Flash Midi Server (FMS) started as an experiment to test communication between Processing and Flash. From there it developed into a

class I played around with a lot – seeing what fun things I could use it for.

As FMS is built in Flash, it allows developers to rapidly prototype audio tools, experiment with new input methods and acess to a huge public code base to

build on top of. There’s a huge amount of technical skill and creativity in the Flash scene and hopefully some of it will be applied to creating innovative

new audio apps using FMS.

HOW DOES IT WORK –

FMS sends data from Flash to the FMS server – which then sends the data as a Midi signal.

Firstly run the FMS app in the “Server App” folder.
Then run one of the Flash or Air apps. Note – you cannot run .swf files as they do not have the security permissions to access the midi server, unless you

set the permissions here – http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html

You can set which Midi Channel the audio is played through via the drop down on the FMS app.
Windows XP has “Microsoft Midi Mapper” which plays the notes back over the soundcard. Mac OSX has a similar default Midi Playback setting.

To use FMS with other audio apps, you must install virtual midi softward. For example – LoopBe http://nerds.de/en/loopbe1.html
These channels will then show up in the FMS settings drop down.

HOW DO I USE THE CLASS MYSELF? –

Place the uk.co.lawriecape.midi folder structure in you classes folder.
You can then check out the .Fla sources in the “Example FLAs” folder.
A basic setup can be seen below –

In flash –

//Import the Flash Midi Server class.
import uk.co.lawriecape.midi.flashMidiServer;
//Create an instance of the class.
var MS: flashMidiServer = new flashMidiServer();
//Add event listeners for the various Server events - (optional)
	MS.addEventListener("FLASH_MIDI_SERVER_ESTABLISHED", connectionEstablishedHandler);
	MS.addEventListener("FLASH_MIDI_SERVER_LOST",        connectionLostHandler);
	MS.addEventListener("FLASH_MIDI_SERVER_NOT_FOUND",   connectionNotFoundHandler);

function connectionEstablishedHandler(e:Event):void{
	trace("Flash midi server connected.");
	trace("You can start sending data now!");
	MS.sendNote(50);
	//or
	//MS.sendCC(50);
}

function connectionLostHandler(e:Event):void{
	trace("Flash midi server disconnected.");
}


function connectionNotFoundHandler(e:Event):void{
	trace("Flash midi server not found, please check the program is running and try again.");
}

WHAT COMES NEXT? –

There are quite a few limitations to the current system, which I’ll be trying to address in future releases. These include –
The ability to send CC data on specified CC numbers.
The ability to have audio output on multiple midi channels at once – to controll multiple instruments from a single server instance.
The ability to send multiple notes at once – eg. Chords or simultaneous drum hits.

If you have any suggestions, or make anything using FMS, please get in touch with me.
Cheers.
Lawrie.

Lawrie at LawrieCape.co.uk

See also –

Flash Midi Server – Sonar reproduction. from Lawrie Cape on Vimeo.

Download the source code for Sonar from the Google Projects Page.

Flash Midi Server – Processing + Flash + Webcam Instrument from Lawrie Cape on Vimeo.

AS3 Quick Tip – Remove a specific item from an array.

I’ve been working on a project today and needed a function to remove a specific item from an array. This is what I came up with, so I thought I’d share it here.

var myArrayOfLetters:Array = ["a","b","c","c","d","e","f","g","c"];
removeItemArray(myArrayOfLetters,"c");
//This will remove all instances of "c" from your array - so you will end up with
//a,b,d,e,f,g
 
function removeItemArray(thearray, theItem):void{
	trace("Remove "+theItem+" from "+thearray);
	for(var i:int=0; i

This will remove all instances of theItem from your array. If you know there will only be one instance of the item in the array, you can add "break;" to the conditional in the loop to save CPU.

var myArrayOfLetters:Array = ["a","b","c","d","e","f","g"];
removeItemArray(myArrayOfLetters,"c");
//This will remove the first instance of "c" from your array - so you will end up with
//a,b,d,e,f,g

function removeItemArray(thearray , theItem):void{
	trace("Remove "+theItem+" from "+thearray );
	for(var i:int=0; i

Hope you find it useful.
Lawrie.

Open Processing

Following on from my post about Daniel Shiffman’s Nature of Code, and the benefits of digging into the processing community, here’s a post about the excellent site OpenProcessing.org

“What? A website to share Processing sketches??”
Share your sketches with others.
Help and collaborate with the community.
Improve and polish your programming skills.

Even if you’re not delving into Processing development yet, there are some amazing examples on the site, which should provide you with some inspiration and ideas, no matter what platform you use. Just check out some of thse incredible pieces –

Empathy –

pEmpathy

Awesome! And here’s the code that makes it –

/** 

Don't move too fast — you might scare it. Click to forgive and forget.

*/ int n = 5000; // number of cells float bd = 37; // base line length float sp = 0.004; // rotation speed step float sl = .97; // slow down rate Cell[] all = new Cell[n]; class Cell{ int x, y; float s = 0; // spin velocity float c = 0; // current angle Cell(int x, int y) { this.x=x; this.y=y; } void sense() { if(pmouseX != 0 || pmouseY != 0) s += sp * det(x, y, pmouseX, pmouseY, mouseX, mouseY) / (dist(x, y, mouseX, mouseY) + 1); s *= sl; c += s; float d = bd * s + .001; line(x, y, x + d * cos(c), y + d * sin(c)); } } void setup(){ size(300, 300, P2D); stroke(0, 0, 0, 20); for(int i = 0; i < n; i++){ float a = i + random(0, PI / 9); float r = ((i / (float) n) * (width / 2) * (((n-i) / (float) n) * 3.3)) + random(-3,3) + 3; all[i] = new Cell(int(r*cos(a)) + (width/2), int(r*sin(a)) + (height/2)); } } void draw() { background(255); for(int i = 0; i < n; i++) all[i].sense(); } void mousePressed() { for(int i=0;i

And that's just one of hundreds of amazing Processing sketches. Here's some more of my favourites.

Scrunch / Flower generator -

pFLower

Spring Snipper -

pSpring

Scattered Letters -

pLetters

Nebula -

pNebula

Spiral Galaxy Mutation -

pGalaxy

Shiffman Vector movement – from Processing to Flash

I’ve been playing about with processing lately, which is really good fun, and quite easy to jump straight into, coming from a Flash background. If you’ve not heard of Processing, it’s –

Processing is an open source project initiated by Casey Reas and Benjamin Fry, both formerly of the Aesthetics and Computation Group at the MIT Media Lab. It is “a programming language and integrated development environment (IDE) built for the electronic arts and visual design communities”, which aims to teach the basics of computer programming in a visual context, and to serve as the foundation for electronic sketchbooks. One of the stated aims of Processing is to act as a tool to get non-programmers started with programming, through the instant gratification of visual feedback. The language builds on the graphical capabilities of the Java programming language, simplifying features and creating a few new ones.

It’s free too! You can grab a copy here.

One of the authorities on Processing is Daniel Shiffman, author of Learning Processing. There’s loads of great content on his site, for the budding developer. One of the most interesting is his section The Nature Of Code. It’s actually the sylabus for a course he teaches, but it makes for great online reading, explaining not only the how, but also the why behind all the programming concepts.

I spent a while digging through the chapter on Vectors (for motion, not graphics), played around with the code in Processing, then ported some of it to Flash.

This is just a quick experiment really, and the code below if not the best way of doing things, but I thought it was an interesting effect none-the-less. Using various vectors in flash, I’ve made a weird springy thing. Move your mouse to swirl it around – press space to restart it – and toggle the limit bounds feature.

[kml_flashembed publishmethod=”static” fversion=”9.0.0″ movie=”flash-content/shiffman/shiffmanVectorsAS3.swf” width=”300″ height=”300″ targetclass=”flashmovie”]

Get Adobe Flash player

[/kml_flashembed]

And here’s the code – uncommented, unoptimised, but you get the idea :)

stage.quality = StageQuality.LOW;
stage.frameRate = 120;
var makeBalls:int = 200;
var movers:Array= [];
var divVar:int = 500;
var mouse = {x:mouseX,y:mouseY}
var springDivider:Number = 25;
var constrainBounds:Boolean = false;
var SW:Number= stage.stageWidth;
var SH:Number= stage.stageHeight;

construct();

function construct():void{
	for (var i:int = 0; i < makeBalls; i++) {
		movers[i] = makeMover(i);
		movers[i].addEventListener(Event.ENTER_FRAME, update);
		addChild(movers[i]);
	}
}

function makeMover(i):DisplayObject{
	
var m:MovieClip = new MovieClip();//new M();

	m.graphics.beginFill( 0xFFCC0000, .5);
	m.graphics.drawCircle(0,0,5);
			
	m.location 		=  {x:SW/2,y:SH/2};
	m.velocity 		=  {x:0,y:0};
	m.acceleration  =  {x:0,y:0};
	m.topspeed 		=  (i/springDivider)+1;
	
	return m;
}


function update(e:Event):void {
	
	var M   = e.currentTarget;
	var dir = {x:mouseX-M.x,y:mouseY-M.y};
	
	M.acceleration.x = dir.x/divVar;
	M.acceleration.y = dir.y/divVar;
	
	M.velocity.x+=M.acceleration.x;
	M.velocity.y+=M.acceleration.y;
	
	if(M.velocity.x>M.topspeed){M.velocity.x=M.topspeed}
	if(M.velocity.y>M.topspeed){M.velocity.y=M.topspeed}
	
	if(M.velocity.x< -M.topspeed){M.velocity.x=-M.topspeed}
	if(M.velocity.y<-M.topspeed){M.velocity.y=-M.topspeed}
	
	M.location.x+=M.velocity.x;
	M.location.y+=M.velocity.y;	
	
	M.x = M.location.x;
	M.y = M.location.y;
	
	if(constrainBounds){
		if (M.location.x > SW) {
			M.location.x = 0;
		} else if (M.location.x < 0) {
			M.location.x = SW;
		}
		if (M.location.y > SH) {
			M.location.y = 0;
		} else if (M.location.y < 0) {
			M.location.y = SH;
		}
	}
}

stage.addEventListener(Event.ENTER_FRAME, updateMouse);
function updateMouse(e:Event):void{
	mouse.x = mouseX;
	mouse.y = mouseY;
}

stage.addEventListener( KeyboardEvent.KEY_UP, keyUpHandler );
function keyUpHandler( e:KeyboardEvent ):void {
	if (e.keyCode==32) {
		
		if(constrainBounds){constrainBounds=false}
		else{constrainBounds=true}
		
		reset();
	}
}

function reset():void{
	for (var i:int = 0; i < makeBalls; i++) {
		movers[i].removeEventListener(Event.ENTER_FRAME, update);
		movers[i].parent.removeChild(movers[i]);
	}
	movers = [];
	construct();
}