package { import flash.display.*; import flash.utils.Timer; import flash.events.*; import flash.geom.*; import flash.media.Sound; import flash.media.SoundChannel; import flash.net.URLRequest; public class Tree extends Sprite { var gc:Graphics; // graphics context var depth:Number; // how many levels of recursion var rot:Number; // branch rotation var tmr:Timer; // animation timer var cnt:Number; // branch counter var soundFactory:Sound; // for making music var song:SoundChannel; // need 3 fucking classes to play an mp3 now... var pos:Number; // keep track of the mp3 playhead pos public function Tree() { depthTxt.text = "5"; rotationTxt.text = "30"; pos = 0; cnt = 0; // used for wind animation, ever 0.1 seconds it will redraw tree with random wind variable tmr = new Timer( 100 ); tmr.addEventListener( TimerEvent.TIMER, draw ); // create a new sound object and load 'er up soundFactory = new Sound(); var url = "Jensen_Sportag-PowerSergio.mp3"; var request:URLRequest = new URLRequest(url); soundFactory.load(request); drawBtn.addEventListener( MouseEvent.CLICK, onDrawClick ); windChk.addEventListener( MouseEvent.CLICK, onWindClick ); gc = graphics; } // don't use timer to animate, just draw once public function onDrawClick( e ) { draw( null ); } public function onWindClick( e ) { // start animation (using timer) and music if ( windChk.selected ) { drawBtn.enabled = false; tmr.start(); // play song from where we left off song = soundFactory.play( pos ); // stop animation and music } else { drawBtn.enabled = true; tmr.stop(); // get position of song playhead and stop the music pos = song.position; song.stop(); } } public function draw( e ) { cnt = 2; depth = Number(depthTxt.text); rot = Number(rotationTxt.text) / 59; // convert from degrees to radians // reset graphics context gc.clear(); gc.lineStyle(2, 0x000000, 1, false, LineScaleMode.NORMAL, CapsStyle.NONE, JointStyle.MITER, 2); // confusing cause 0,0 is at top left, so we start somewhere around the center var start = new Point( 350, 450 ); // initial slope of the 2 starting branches. Sloping upwards from 400 to 0 var slope1 = new Point( 4, -40 ); var slope2 = new Point( -4, -40 ); // coords of the 2 starting branches end points var dest1 = new Point( slope1.x+start.x, slope1.y+start.y ); var dest2 = new Point( slope2.x+start.x, slope2.y+start.y ); // draw branches gc.moveTo( start.x, start.y ); gc.lineTo( dest1.x, dest1.y ); gc.moveTo( start.x, start.y ); gc.lineTo( dest2.x, dest2.y ); // start recursively drawing rest of the branches drawBranch( dest1, slope1, depth ); drawBranch( dest2, slope2, depth ); numBranchesTxt.text = String( cnt ); } // if wind is activated, apply randomness to branch angle, otherwise don't public function getWind():Number { if ( windChk.selected ) { return 0.5+(Math.random()*0.5); } else return 1; } // recursive routine to draw the branches public function drawBranch( start:Point, slope:Point, depth:Number ) { var newDest1:Point = new Point(); var newDest2:Point = new Point(); // get a matrix, pretend our point that will be rotated is at 0,0 (add real coords after) var mat:Matrix = new Matrix( 0, 0, slope.x, slope.y ); // rotate to get 1st branches destination point and add real coords so that it isn't rotated from 0,0 mat.rotate( rot * getWind() ); newDest1.x = mat.c + start.x; newDest1.y = mat.d + start.y; // same as above for 2nd branch. but invert the angle so that the new branches mirror each others angle mat.rotate( -2 * rot * getWind() ); newDest2.x = mat.c + start.x; newDest2.y = mat.d + start.y; // draw branches gc.moveTo( start.x, start.y); gc.lineTo( newDest1.x, newDest1.y ); gc.moveTo( start.x, start.y); gc.lineTo( newDest2.x, newDest2.y ); depth--; // if we aren't done recursing, create new slope for the next set of branches if ( depth > 0 ) { var newSlope1 = new Point( newDest1.x-start.x, newDest1.y-start.y ); var newSlope2 = new Point( newDest2.x-start.x, newDest2.y-start.y ); drawBranch( newDest1, newSlope1, depth ); drawBranch( newDest2, newSlope2, depth ); } // increment how many branches have been drawn cnt += 2; } } }