Browse the notebook

Category: functions

Object.constructor()

var Box:Function = {
	constructor : function(color:uint, w:Number, h:Number):void {
		this.color = color;
		this.s = new Shape();
		with(this.s.graphics) beginFill(this.color), drawRect(0,0,w,h);
		addChild(this.s);
		
		this.setLoc = function(x:Number, y:Number):void{
			this.s.x = x;
			this.s.y = y;
	   }
	}
}.constructor;

var box0:Object = new Box(0xFF0000, 100, 100);

box0.setLoc(100, 10);

var box1:Object = new Box(0x000000, 50, 50);

box1.setLoc(210, 10);

This snippet makes use of Object.constructor() to allow creation of Object instances using the new keyword. This is for fun only, I don’t recommend this over actual Classes.

Read snippet: Object.constructor()

Circle of Particles

var canvas:BitmapData = new BitmapData(400,400, false, 0xFFFFFF);
addChild(new Bitmap(canvas));
var eraser:BitmapData = new BitmapData(400,400, true, 0x33FFFFFF);

var particles:Array = new Array();
for (var i:int = 0; i < 1000; i++){
	particles.push(makeParticle());
}

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	canvas.copyPixels(eraser, eraser.rect, new Point(0,0), null, null, true);
	for (var i:int = 0; i < particles.length; i++){
		particles[i]();
	}
}

function makeParticle():Function {
	var dx:Number, dy:Number;
	var x:Number = 200;
	var y:Number = 200;
	var vx:Number = Math.random() * 4 - 2;
	var vy:Number = Math.random() * 4 - 2;
	return function():void {
			  x += vx;
		      y += vy;
		      dx = x - 200;
		      dy= y - 200;
			   if (Math.sqrt((dx * dx) + (dy * dy)) > 100){
				 vx *= -1;
				 vy *= -1;
			   }
		       canvas.setPixel(x, y, 0x000000);
	}
}

This creates a circular area filled with moving particles/pixels. It makes use of yesterdays functional programming techniques.

Read snippet: Circle of Particles

Functional Pseudo-Objects

var moverNum:int = 40;
var movers:Array = new Array();

for (var i:int = 0; i<moverNum; i++){
	movers.push(makeMover());
}

addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	for (var i:int = 0; i<moverNum; i++){
		movers[i]();
	}
}

function makeMover():Function{
	// mover vars & setup
	var xVel:Number = Math.random() * 5 + 1;
	var right:Number = stage.stageWidth + 30;
	var s:Shape = Shape(addChild(new Shape()));
	with(s.graphics) beginFill(0xFF0000), drawCircle(0,0,5);
	s.x = Math.random() * stage.stageWidth;
	s.y = Math.random() * stage.stageHeight;
	// return a "run" function
	return function():void {
		 s.x += xVel;
		 if (s.x > right){
			s.x = -30; 
		 }
	}
}

This snippet creates 40 shapes that move to the right at a random velocity. When they animate off the right hand side of the stage they return from the left.

The makeMover() function has a series of variable definitions related to the x velocity and position of a Shape. The makeMover() function then returns an anonymous function that contains some logic to move the Shape “s”. The anonymous function has access to the makeMover() functions temporary variables…

On the main loop we run all of the anonymous functions – animating all the shapes by their random x velocities.

It would be interesting to write the same program using classes and test the for speed differences. My assumption is that anonymous functions are expensive, but it would still be interesting to see…

Read snippet: Functional Pseudo-Objects

Readable Conditionals

// NOTE: this code won't do anything in you're timline....

// do you do this?

if (ball.x < 0 || ball.y < 0 || ball.x > stage.stageWidth || ball.y > stage.stageHeight){
       // cause ball to explode
}

// or this?

if (isAtStageEdge(ball)){
       // cause ball to explode
}

function isAtStageEdge(mc:MovieClip):Boolean{
   return (mc.x < 0 || mc.y < 0 || mc.x > stage.stageWidth || mc.y > stage.stageHeight);
}

This is pretty standard stuff, but it can increase code readability especially for complex conditionals.

I also do this if I find myself repeating an a semi-complex if statement in two or more places.

If I’m just brainstorming I probably won’t bother, but on real projects it helps keep code readable.

Read snippet: Readable Conditionals

Graphics Class Methods in XML

// for simplicity I left this XML inline, this will work exactly the same if it were external
var program:XML=<body>
				<draw>
				  <![CDATA[
				   beginFill(0xFF0000);
				   drawCircle(100,100,50);
				   endFill();
				   lineStyle(0, 0x666666);
				   moveTo(100, 100);
				   lineTo(200, 200);
				   moveTo(300, 200);
				   curveTo(350, 300, 400, 200);
				   lineStyle(0, 0x0000FF);
				   drawRect(200, 50,100,100) ;
					]]>
				</draw>
</body>;

// parse and run the Graphics class commands from the XML
render(parseFunctions(program.draw.toString()));

function parseFunctions(dat:String):Array{
	var a:Array = dat.split(";") ;
	for (var i:int = 0; i<a.length-1; i++){
		a[i] = a[i].split(/()|(|)/g);
		var f:String = a[i][0] = a[i][0].replace(/s/g,"");
		a[i] = a[i].splice(0, a[i].length - 1);
		if (a[i].length> 1){
		 a[i] = a[i][1].split(",");
		 a[i].unshift(f);
		}
	}
	return a.splice(0,a.length - 1);
}
function render(p:Array):void {
	for (var i:int = 0; i<p.length; i++) {
		graphics[p[i][0]].apply(graphics,p[i].splice(1));
	}
}

The above code builds on yesterdays post by showing how one could potentially store graphics class method calls in XML using a few regular expressions and Function.apply().

The parseFunctions() function reads through the CDATA string and formats it in a 2D array that looks like this:

[[beginFill, 0xFF0000], [drawCircle, 100, 100, 50], etc...]

The render() function reads through this 2D array, using the first value of each nested array as the function and the remaining values as arguments…

As is this won’t really work with most of the new fp10 graphics methods…

Read snippet: Graphics Class Methods in XML

Dynamic Graphics and Function.apply()

var cmds:Array = [["lineStyle", 0, 0xFF0000], ["drawCircle",100, 100, 50], ["drawRect", 50, 50, 100, 100]];
cmds.push(["drawCircle", 100, 100, 70]);
cmds.push(["beginFill",  0x555555]);
cmds.push(["drawRoundRect", 80, 80, 40, 40, 10, 10]);
cmds.push(["endFill"]);

render(cmds);

function render(p:Array):void {
	for (var i:int = 0; i<p.length; i++) {
		graphics[p[i][0]].apply(graphics,p[i].splice(1));
	}
}

The above creates a function called render() that takes a 2D array of Graphics class methods and then runs them. This is a very interesting technique, specifically if you’d like to write Graphics class method calls in an XML or txt file and then have them run on a given DisplayObject in flash.

I’ve been thinking about the best way to do this for awhile… I started off doing something very convoluted and then realized that I could use Function.apply()….

Tomorrow I’ll post a snippet showing how to use this function in conjunction with XML.

Read snippet: Dynamic Graphics and Function.apply()

nesting(function(calls()))

[SWF(width=500, height=500, backgroundColor=0x000000, frameRate=30)]

for (var i:int = 0; i<10; i++){
       // draggable ellipse
	var dot:Sprite = drag(createSprite("Ellipse",  -10, -10, 20, 20));
	dot.x = Math.random() * stage.stageWidth ;
	dot.y = Math.random() * stage.stageHeight ;
}

for (i = 0; i<10; i++){
  
      var box:Sprite = drag(spin(createSprite("Rect", -20, -20, 40, 40, 0xFF0000), Math.random()*5 + 1));
	box.x = Math.random() * stage.stageWidth ;
	box.y = Math.random() * stage.stageHeight ;
}


 // createSprite can create ellipses or rectangles
function createSprite(shape:String, xp:Number, yp:Number, w:Number, h:Number, col:uint=0x444444):Sprite {
	var s:Sprite = new Sprite();
	s.graphics.beginFill(col);
	// trick from a previous post
	s.graphics["draw" + shape](xp, yp, w, h);
	addChild(s);
	return s;
}

// drag and spin add listeners to an untyped target and return that target for easy function nesting
function drag(target:*):*{
	target.addEventListener(MouseEvent.MOUSE_DOWN, function(evt:MouseEvent){ evt.currentTarget.startDrag(); });
	return target;
}

function spin(target:*, speed:Number):*{
	target.addEventListener(Event.ENTER_FRAME, function(evt:Event){ evt.currentTarget.rotation+=speed; });
	return target;
}

stage.addEventListener(MouseEvent.MOUSE_UP, function(){ stopDrag() });

The above will create some draggable circles and some rotating draggable rects… but that’s not really the point….

When prototyping and just playing around I write functions that take an Object as an argument, alter that Object in some way and pass that some Object out as a return value…. this makes it so I can write things like this:

drag(spin(createSprite("Rect", -20, -20, 40, 40, 0xFF0000), Math.random()*5 + 1));

Readability can be a problem so… consider that before using this for anything…

Read snippet: nesting(function(calls()))

Constants as Function Argument Defaults

const RADIUS = 10;
const COLOR = 0xCCCCCC;

function createCircle(xp:Number, yp:Number, radius:Number = RADIUS, col:uint = COLOR):void{
	var c:Sprite = new Sprite();
	c.graphics.beginFill(col);
	c.graphics.drawCircle(xp, yp, radius);
	addChild(c);
}

// optional last 2 values are populated with const defaults
createCircle(100,100);
// optional color value is populated with default 0xCCCCCC;
createCircle(200,100, 20);
//
createCircle(300,100, 50,0x0000FF);
Read snippet: Constants as Function Argument Defaults

Recursive Tree

var branches:int = 0;
var maxBranches:int = 400;
 
graphics.lineStyle(0,0x000000);

makeBranch(300,350,100,-45,45);
	 
function makeBranch(xp:Number, yp:Number, leng:Number, min:Number, max:Number):void {

	var endX:Number, endY:Number;
	var theta:Number = (min + Math.random()*(max-min) - 90) * Math.PI / 180;
	 
	endX = xp + leng * Math.cos(theta);
	endY = yp + leng * Math.sin(theta);

	graphics.moveTo(xp, yp);
	graphics.lineTo(endX, endY);
	
	if (branches < maxBranches) {
		var newLength:Number = leng*.7; 
		setTimeout(makeBranch, 0, endX, endY, newLength, -90, 0);
		setTimeout(makeBranch, 0, endX, endY, newLength, 0, 90);
	}
	branches+=2;
}

Draws a tree using recursion.

Read snippet: Recursive Tree

Recursion Trick w/ setTimeout()

var counter:int = 0;

graphics.lineStyle(0,0x000000);

recursive();

function recursive():void{
	
	if (counter < 4000){
	   graphics.moveTo(10,10);
	   graphics.lineTo(counter, 200);
	   counter+=4;
          // don't call recursive(), use setTimeout instead
	   setTimeout(recursive,0);
	}else{
		trace(counter / 4 + " lines were drawn");
	}

Be careful with this one, if you don’t know what your doing you may be able to crash flash.

Anyway… if you use a recursive function in flash you may find yourself getting a stack overflow error. You can avoid this by using setTimeout():

 // don't call recursive(), use setTimeout() instead
setTimeout(recursive,0);

Of course… the stack overflow error is there for a reason, if used incorrectly you could bring the flash player to a standstill.

You can also achieve animated recursion by actually adding a delay to your setTimout() call:

 // don't call recursive(), use setTimeout() instead
setTimeout(recursive,10);
Read snippet: Recursion Trick w/ setTimeout()