Interactive Generative Art Series – 08 – multiple lines scalable


Well, so much for blogging each step in my process of creating this generative art series. I took a few steps in this iteration since the last one. But it was all in the spirit of one step. First I wanted to abstract the duplication of each ball/line so that it didn’t require copying blocks of code for each one. The obvious route is to have a var that designates the number of balls which will draw lines, and then loop through creating the desired number and then in the loop function that is executed each frame loop through them again and draw new lines for each one. This was pretty simple, in the end, and I ended up adding quite a few variables to differentiate each line for the others in line width, color variation and position. I also added a few function to help with calculations and updated the alpha values of the lines. The normalize, interpolate and map functions I acquired long ago from kp here, go there to hear his explanation which is much better than any attempt I could make. Thanks Keith!



Then, I had the task of making it more manageable and scalable. Before these edits, the framerate would sink to around 6 in the first 10 seconds of running with more than 3 lines. After some research it seemed the performance suffered mainly because the graphics drawn with transparency had to figure every single line on the stage to determine it’s color values and flash doesn’t do that too efficiently. So the solution was to use the bitmap and bitmapdata objects. Every frame I copy what has been drawn on the stage into a bitmapdata objects and set it to display on the stage instead. This essentially lets flash calculate the alpha values for each line once and then copy it as simple pixel data for later frames. It happens every frame and is in the flush function. It worked better than I had hoped. I could ramp up the number of lines to 40 and still not see any frame rate slowdown in FPS.

08 multiple lines scalable, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart8a” movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-08-multiple-lines-scalable.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

08 multiple lines scalable, another instance

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart8b” movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-08-multiple-lines-scalable.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var balls:Array = new Array(); // array of ball objects – each ball object stores it’s own position (current & previous), acceleration, etc
var num_balls:int = 0;
var total_balls:int = 12;
var canvas:Sprite = new Sprite();
this.addChild(canvas);

//copy the graphics on stage to a bitmap, then next frame draw on it.
var bitmapcanvasdata:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x000000);
//draw stage to bitmap
bitmapcanvasdata.draw(canvas);
var bitmapcanvas:Bitmap = new Bitmap(bitmapcanvasdata);
//put bitmap on stage
this.addChild(bitmapcanvas);

function createBall():void{
var ball_o:Object = new Object();

var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, .5);
ball.graphics.drawCircle(0, 0, 3);
ball.graphics.endFill();
addChild(ball);
ball_o.ball = ball;

ball_o.x = randomRangeAxis(10);
ball_o.y = 0;
ball_o.ax = 0;
ball_o.ay = 0;
ball_o.oldx = ball_o.ball.x;
ball_o.oldy = ball_o.ball.y;
ball_o.gradientBoxMatrix = new Matrix();
ball_o.drift = randomRangeAxis(10);
ball_o.color_drift = Math.floor(randomRangeAxis(4)) * 1024;
ball_o.line_width_drift = randomRangeAxis(2);
balls.push(ball_o);
}

for (var i:int = 0; i < total_balls; i++){ createBall(); }var anchor:Sprite = new Sprite();anchor.graphics.beginFill(0x333333, .6); anchor.graphics.drawCircle(0, 0, 12); anchor.graphics.endFill(); addChild(anchor);var div:Number = .1; var line_max_width:Number = 64; var line_min_width:Number = 1; var line_width:Number = randomRange(line_min_width, line_max_width); var line_width_velocity:Number = 0; var dampen:Number = 0.95;var anchorvx:Number = 0; var anchorvy:Number = 0;anchor.x = stage.stageWidth/2; anchor.y = stage.stageHeight/2;var colors:Object = new Object(); colors.r = 150; colors.g = 100; colors.b = 200; colors.rv = 0; colors.gv = 0; colors.bv = 0; colors.rd = 100; colors.gd = 150; colors.bd = 200; colors.rmin = randomRange(0, 30); //0 colors.rmax = randomRange(colors.rmin, colors.rmin + colors.rd); //100 colors.gmin = randomRange(0, 60); //100 colors.gmax = randomRange(colors.gmin, colors.gmin + colors.gd); //200 colors.bmin = randomRange(0, 50); //150 colors.bmax = randomRange(colors.bmin, colors.bmin + colors.bd); //250 colors.rate_of_change = 10; var color_first:Number = 0xFFFFFF; var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);function loop (e:Event = null) { //anchor anchorvx += randomRangeAxis(10); anchorvy += randomRangeAxis(10); anchor.x += anchorvx; anchor.y += anchorvy; anchorvx *= dampen; anchorvy *= dampen; if(anchor.x > stage.stageWidth) anchor.x = 0 – anchor.width;
else if(anchor.x < 0 - anchor.width) anchor.x = stage.stageWidth; if(anchor.y > stage.stageHeight) anchor.y = 0 – anchor.height;
else if(anchor.y < 0 - anchor.height) anchor.y = stage.stageHeight; //linewidth line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) { line_width = line_min_width; line_width_velocity = 0; } //color step color_step(); color_first = color_second; color_second = rgb2hex(colors.r, colors.g, colors.b); //loop through balls and draw lines for (var i:int = 0; i < total_balls; i++){ balls[i].oldx = balls[i].ball.x; balls[i].oldy = balls[i].ball.y; balls[i].ball.x -= balls[i].ax = (balls[i].ax + (balls[i].ball.x - (anchor.x + randomRangeAxis(line_width * balls[i].drift))) * div) * .9; balls[i].ball.y -= balls[i].ay = (balls[i].ay + (balls[i].ball.y - (anchor.y + randomRangeAxis(line_width * balls[i].drift))) * div) * .9; balls[i].dx = balls[i].x - balls[i].oldx; balls[i].dy = balls[i].y - balls[i].oldy; canvas.graphics.moveTo(balls[i].oldx, balls[i].oldy); canvas.graphics.lineStyle(randomRangeAxis(balls[i].line_width_drift,line_width), color_first, 1, true, LineScaleMode.NONE, CapsStyle.NONE); balls[i].gradientBoxMatrix.createGradientBox(Math.abs(balls[i].dx), Math.abs(balls[i].dy), Math.atan2(balls[i].dy,balls[i].dx), Math.min(balls[i].oldx, balls[i].ball.x), Math.min(balls[i].oldy, balls[i].ball.y)); canvas.graphics.lineGradientStyle(GradientType.LINEAR, [color_first + balls[i].color_drift, color_second + balls[i].color_drift], [map(line_width,line_max_width,line_min_width, .1, .9),map(line_width,line_max_width,line_min_width, .1, .9)], [0, 255], balls[i].gradientBoxMatrix); canvas.graphics.lineTo(balls[i].ball.x, balls[i].ball.y); } //copy graphics drawings to bitmapdata and clear graphics flush(); } function flush():void { //draw stage to bitmap bitmapcanvasdata.draw(canvas); //replace bitmapdata of bitmap bitmapcanvas.bitmapData = bitmapcanvasdata; //erase vectors on stage canvas.graphics.clear(); }this.addEventListener(Event.ENTER_FRAME, loop)function rgb2hex(r:Number, g:Number, b:Number):Number { return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(colors.rate_of_change); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){ colors.r = colors.rmin; } colors.gv += randomRangeAxis(colors.rate_of_change); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){ colors.g = colors.gmin; } colors.bv += randomRangeAxis(colors.rate_of_change); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){ colors.b = colors.bmin; } } //random number between min and max function randomRange(max:Number, min:Number = 0):Number { return Math.random() * (max - min) + min; } //random number range centered at 0 with the specified max, randomRange(-max, max) function randomRangeAxis(max:Number, axis:Number = 0):Number { return Math.random() * (max * 2) - max + axis; } //normalize(value, min, max) takes a value within a given range and converts it to a number between 0 and 1 (actually it can be outside that range if the original value is outside its range). function normalize(value:Number, minimum:Number, maximum:Number):Number { return (value - minimum) / (maximum - minimum); } //interpolate(min, max, value) is linear interpolation. It takes a normalized value and a range and returns the actual value for the interpolated value in that range. function interpolate(normValue:Number, minimum:Number, maximum:Number):Number { return minimum + (maximum - minimum) * normValue; } //map(value, min1, max1, min2, max2) takes a value in a given range (min1, max1) and finds the corresonding value in the next range(min2, max2). function map(value:Number, min1:Number, max1:Number, min2:Number, max2:Number):Number { return interpolate( normalize(value, min1, max1), min2, max2); } [/cc]

download

Here’s the gen-art-08-multiple-lines-scalable.swf as well as the gen-art-08-multiple-lines-scalable.fla to download and explore. And as always if you’ve got ideas or suggestions, comment below. One thing I’m struggling with is that now although the experiment is truly generative, it’s no longer interactive.

Interactive Generative Art Series – 07 – multiple lines

gen-art-multi-lines 01gen-art-multi-lines 02gen-art-multi-lines 03

To make it more interesting and give more depth and texture to the display, I wanted to have more lines than one, so I’m now going with two for starters. Eventually I’d like to get up to a dozen or maybe even have them randomly self populate and die over time. Adding one more isn’t a whole lot of code, but it did require a bit of rearranging. I created a sprite container for each line, and then basically doubled any var used by one line for the other. When calculating the position for the second line I added a bit of randomness, so it wouldn’t be drawn in the exact same position of the first line. Plus, when drawing the second line I adjust the alpha/transparency a bit and the line width. A big issues that I notice right away is that the memory noticeably begins to suffer after a bit of drawing. After some investigation I determined it is (at least in part) the fact that the lines now have to blend with the lines below them with transparency. If I set the alpha properties in the lineGradientStyle to 1 and 1 the performance is much better. Any ideas of how to fix this? I’m guessing I should start investigating bitmap data.

07 multiline, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart7″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-07-multilines.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 1);
ball.graphics.drawCircle(0, 0, 10);
ball.graphics.endFill();
addChild(ball);
var ball2:Sprite = new Sprite();
ball2.graphics.beginFill(0x000000, 1);
ball2.graphics.drawCircle(0, 0, 5);
ball2.graphics.endFill();
addChild(ball2);

var balllines:Sprite = new Sprite();
addChild(balllines);
var ball2lines:Sprite = new Sprite();
addChild(ball2lines);

var anchor:Sprite = new Sprite();

anchor.graphics.beginFill(0x333333, .6);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);

var div:Number = .1;
var line_max_width:Number = 64;
var line_min_width:Number = 1;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var ball2ax:Number = 0;
var ball2ay:Number = 0;
var old2x:Number = ball2.x;
var old2y:Number = ball2.y;

var anchorvx:Number = 0;
var anchorvy:Number = 0;

anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
ball2.x = randomRangeAxis(10);
var gradientBoxMatrix:Matrix = new Matrix();

var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 150; //0
colors.rmax = 250; //100
colors.gmin = 0; //100
colors.gmax = 150; //200
colors.bmin = 0; //150
colors.bmax = 100; //250
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);

function loop () {

oldx = ball.x;
oldy = ball.y;
old2x = ball2.x;
old2y = ball2.y;

anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);

anchor.x += anchorvx;
anchor.y += anchorvy;

anchorvx *= dampen;
anchorvy *= dampen;

if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 - anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 - anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x - anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y - anchor.y) * div) * .9; ball2.x -= ball2ax = (ball2ax + (ball2.x - (anchor.x + randomRangeAxis(line_width * 2))) * div) * .9; ball2.y -= ball2ay = (ball2ay + (ball2.y - (anchor.y + randomRangeAxis(line_width * 2))) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) { line_width = line_min_width; line_width_velocity = 0; } color_step(); color_first = color_second; color_second = rgb2hex(colors.r, colors.g, colors.b); var dx:Number = ball.x - oldx; var dy:Number = ball.y - oldy; balllines.graphics.lineStyle(line_width, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE); gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y)); balllines.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [(line_width+100-line_max_width)/100,(line_width+100-line_max_width)/100], [0, 255], gradientBoxMatrix); balllines.graphics.lineTo(ball.x, ball.y); dx = ball2.x - old2x; dy = ball2.y - old2y; ball2lines.graphics.lineStyle(line_width/2, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE); gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(old2x, ball2.x), Math.min(old2y, ball2.y)); ball2lines.graphics.lineGradientStyle(GradientType.LINEAR, [color_first + 3072, color_second + 3072], [((line_width/2)+100-line_max_width)/100,((line_width/2)+100-line_max_width)/100], [0, 255], gradientBoxMatrix); ball2lines.graphics.lineTo(ball2.x, ball2.y); }setInterval(loop, 1000/30);function rgb2hex(r:Number, g:Number, b:Number):Number { return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(colors.rate_of_change); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){ colors.r = colors.rmin; } colors.gv += randomRangeAxis(colors.rate_of_change); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){ colors.g = colors.gmin; } colors.bv += randomRangeAxis(colors.rate_of_change); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){ colors.b = colors.bmin; } } //random number between min and max function randomRange(max:Number, min:Number = 0):Number { return Math.random() * (max - min) + min; } //random number range centered at 0 with the specified max, randomRange(-max, max) function randomRangeAxis(max:Number, axis:Number = 0):Number { return Math.random() * (max * 2) - max + axis; } [/cc]

download

Here’s the gen-art-07-multilines.swf as well as the gen-art-07-multilines.fla to download and tinker.

Interactive Generative Art Series – 06 – lineStyle

gen-art-06-linestyle-1gen-art-06-linestyle-2gen-art-06-linestyle-3

The last example in this series discussed getting the anchor to move in a way that our ball would paint more interesting and we worked on restricting the colors to a certain RGB range. This one is a very simple change, but has a pretty significant effect. We’re just editing the cap style of our lines in lineStyle. The default value we’ve been using so far is ROUND, but now if we test NONE the lines drawn will have no ends and basically be rectangles (since the width is so wide). This gets interesting especially when the path curves and we can see all the angles and corners exposed by the rectangles and it makes me think of a wooden snake toy (Wooden Wiggle Snake). I started playing around with the opacity or alpha property of the lines as well so that the flat ended lines would show better. What else would you toy with in here?

06 lineStyle, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-6″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-06-linestyle.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 1);
ball.graphics.drawCircle(0, 0, 10);
ball.graphics.endFill();
addChild(ball);

var anchor:Sprite = new Sprite();

anchor.graphics.beginFill(0x333333, .6);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);

var div:Number = .1;
var line_max_width:Number = 64;
var line_min_width:Number = 2;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;

var anchorvx:Number = 0;
var anchorvy:Number = 0;

anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
var gradientBoxMatrix:Matrix = new Matrix();

var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 0;
colors.rmax = 150;
colors.gmin = 100;
colors.gmax = 200;
colors.bmin = 200;
colors.bmax = 250;
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);

function loop () {

oldx = ball.x;
oldy = ball.y;

anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);

anchor.x += anchorvx;
anchor.y += anchorvy;

anchorvx *= dampen;
anchorvy *= dampen;

if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 - anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 - anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x - anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y - anchor.y) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) { line_width = line_min_width; line_width_velocity = 0; } color_step(); color_first = color_second; color_second = rgb2hex(colors.r, colors.g, colors.b); var dx:Number = ball.x - oldx; var dy:Number = ball.y - oldy; this.graphics.lineStyle(line_width, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE); gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y)); this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [(line_width+100-line_max_width)/100,(line_width+100-line_max_width)/100], [0, 255], gradientBoxMatrix); this.graphics.lineTo(ball.x, ball.y); }setInterval(loop, 1000/30);function rgb2hex(r:Number, g:Number, b:Number):Number { return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(colors.rate_of_change); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){ colors.r = colors.rmin; } colors.gv += randomRangeAxis(colors.rate_of_change); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){ colors.g = colors.gmin; } colors.bv += randomRangeAxis(colors.rate_of_change); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){ colors.b = colors.bmin; } } //random number between min and max function randomRange(max:Number, min:Number = 0):Number { return Math.random() * (max - min) + min; } //random number range centered at 0 with the specified max, randomRange(-max, max) function randomRangeAxis(max:Number, axis:Number = 0):Number { return Math.random() * (max * 2) - max + axis; } [/cc]

download

Here’s the gen-art-06-linestyle.swf as well as the gen-art-06-linestyle.fla to download and tinker.

Reference

Interactive Generative Art Series – 05 – wild anchor

gen-art-05-wild-anchor-1gen-art-05-wild-anchor-2gen-art-05-wild-anchor-3

While in the previous step (Generative Art 04 Using a target other than the mouse) in this generative actionscript art tutorial series it was cool to see everything move on it’s very own, it seemed a bit slow or fake, or maybe just plain uninteresting. Tinkering with the color, I thought if we set a minimum and maximum value for each red green and blur we could control the colors a bit more and still let them be generative. Plus I wanted the anchor to move a bit more and thus paint the curves and lines in a more interesting fashion. To do this we ramp up the range of the change rate of the anchor velocity. I really enjoy this example because it is faster, so we get more of those sweeping arcs, but also when the anchor slows down we get some very delicate curves and twists. With just a couple changes from the last example (which frankly seemed a bit chaotic), now I’m starting to see for the first time how to set some controls in the code which will lead to a visually appealing and still randomly generative result.
gen-art-05-wild-anchor-4gen-art-05-wild-anchor-5gen-art-05-wild-anchor-6

For some reason I find it gratifying that the final swf is still a mere 2kb and change. Perhaps all this current focus on HD and 3D gives us the sense that to be good it needs to have a large footprint. Sometimes the magic or value is in how much you can accomplish with less (less is more)

05 Wild Anchor, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-05-wild-anchor.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, .5);
ball.graphics.drawCircle(0, 0, 5);
ball.graphics.endFill();
addChild(ball);

var anchor:Sprite = new Sprite();
anchor.graphics.beginFill(0x333333, .5);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);

var div:Number = .1;
var line_max_width:Number = 48;
var line_min_width:Number = 1;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;

var anchorvx:Number = 0;
var anchorvy:Number = 0;

anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;

var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 150; //0
colors.rmax = 250; //100
colors.gmin = 0; //100
colors.gmax = 150; //200
colors.bmin = 0; //150
colors.bmax = 100; //250
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();

function loop () {

oldx = ball.x;
oldy = ball.y;

anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);

anchor.x += anchorvx;
anchor.y += anchorvy;

anchorvx *= dampen;
anchorvy *= dampen;

if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 – anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 – anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x – anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y – anchor.y) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}

color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);

var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [0, 255], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}

setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(colors.rate_of_change); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){ colors.r = colors.rmin; } colors.gv += randomRangeAxis(colors.rate_of_change); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){ colors.g = colors.gmin; } colors.bv += randomRangeAxis(colors.rate_of_change); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){
colors.b = colors.bmin;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}

[/cc]

download

View the swf and get the fla source file.

Interactive Generative Art Series – 04 – anchor



Thanks for keeping up with this random generative art series. I know I’m having a ball just playing with code one step at a time. To watch each iteration, I was getting tired of drawing with my mouse to see the generative art, and as others had pointed out, in order for it to truly be generative, it shouldn’t depend on me moving my mouse. So instead of using the mouse position as my target anchor, I created a new node named anchor. This anchor I’m animating with simple random brownian motion which I’ve blogged about before. It just meanders along the stage as it pleases and the other ball will “chase” it just like it chased your mouse in the previous examples. The part that gets exciting is that my anchor wraps from one side of the stage to the other, while the ball does not. One second it’s target is far right and the next it switches to far left, this makes for some really interesting paths and lines. Experiment with the velocity of the anchor in lines 47 + 48 to see interesting effects. One thing I’m beginning to notice however is the performance of the little app gets a bit slower the longer you let it run, perhaps I didn’t realize it before since I didn’t have the attention to keep moving my mouse and watching it follow, now that it truly is generative (and less interactive btw), I watch it longer (seems kind of backwards to what I’d expect).

Note: in this example I have the anchor ball visible, as well as the other ball, but for an actual production, I’d have them both hidden and the lines just appearing. I prefer it that way but though you’d better see what was actually happening with them visible, even though it kills some of the magic. It’s like watching a magic trick when you already know how it’s done.

04 Anchor, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-4″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-04-anchor.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 0);
ball.graphics.drawCircle(0, 0, 5);
ball.graphics.endFill();
addChild(ball);

var anchor:Sprite = new Sprite();

anchor.graphics.beginFill(0x333333, 0);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);

var div:Number = .1;
var line_max_width:Number = 42;
var line_min_width:Number = 2;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;

var anchorvx:Number = 0;
var anchorvy:Number = 0;

anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;

var colors:Object = new Object();
colors.r = 0;
colors.g = 122;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.min = 0;
colors.max = 200;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();

function loop ()
{
oldx = ball.x;
oldy = ball.y;

anchorvx += randomRangeAxis(2);
anchorvy += randomRangeAxis(2);

anchor.x += anchorvx;
anchor.y += anchorvy;

anchorvx *= dampen;
anchorvy *= dampen;

if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 – anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 – anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x – anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y – anchor.y) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}

color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);

var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [85, 170], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}

setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += Math.random() * 20 – 10; colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.max) {
colors.r = colors.max;
} else if (colors.r < colors.min){ colors.r = colors.min; } colors.gv += Math.random() * 20 – 10; colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.max) {
colors.g = colors.max;
} else if (colors.g < colors.min){ colors.g = colors.min; } colors.bv += Math.random() * 20 – 10; colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.max) {
colors.b = colors.max;
} else if (colors.b < colors.min){
colors.b = colors.min;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}

[/cc]

download

swf and fla source file.

Interactive Generative Art Series – 03 – Gradient Colors

genart-03-gradient-color-1genart-03-gradient-color-2genart-03-gradient-color-3

With the full range of colors randomly available to me, I wanted to get a more fluid randomly created color. I see the hard line breaking one color from the next in the generative art 02 random color experiment. I wanted to have the lines drawn between my 2 points to be a gradient of two colors rather than solid color followed by solid color. In this attempt at a smoother color transition, I needed to better understand the gradientBoxMatrix and createGradientBox. I knew visually what I wanted to accomplish but had to brush up on the docs and then experiment a bit to get the math right. The hard line color change still shows in places, but it’s only when one line is short enough and then is overwritten by the beginning of the next line, so technically it’s doing what I intended, but visually it’s still not as gradual as I was wanting. I could toy a bit more with the rate of color change, but I feel pretty accomplished after having figured out that trigonometry and arc-tangent.

03 Gradient Color, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart-3″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-03-gradient-color.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();

ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);

var oldx:Number = ball.x;
var oldy:Number = ball.y;

var div:Number = .1;

var ax:Number = 0;
var ay:Number = 0;

var line_max_width:Number = 75;
var line_min_width:Number = 5;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var colors:Object = new Object();
colors.r = 0;
colors.g = 122;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.min = 0;
colors.max = 155;
var color_first:Number = 0x000000;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();

function loop () {
oldx = ball.x;
oldy = ball.y;

ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;

line_width_velocity += randomRangeAxis(3);
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }

color_first = color_second;
color_step();
color_second = rgb2hex(colors.r, colors.g, colors.b);

var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [85, 170], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}

setInterval(loop, 1000/30);

function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(10); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.max) {
colors.r = colors.max;
} else if (colors.r < colors.min){ colors.r = colors.min; } colors.gv += randomRangeAxis(10); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.max) {
colors.g = colors.max;
} else if (colors.g < colors.min){ colors.g = colors.min; } colors.bv += randomRangeAxis(10); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.max) {
colors.b = colors.max;
} else if (colors.b < colors.min){
colors.b = colors.min;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}
[/cc]
You’ll see I introduced a few new methods into this example. I wanted to simplify my random number generation so I created a couple separate functions to create a random number within a certain range, one given a min and max and another to give a random range around an axis, so for example a number between -10 and +10.

download

Here’s the gen-art-03-gradient-color.swf and gen-art-03-gradient-color.fla.

Resources

Interactive Generative Art Series – 02 – Random Color

gen-art-02-1gen-art-02-2gen-art-02-3

With this example we’re taking a look at having randomly changing color. I liked the limits to the color in the last post, but couldn’t help myself and wanted to see it with the full range of colors to command. Also, I wasn’t a huge fan when the color would “wrap” and jump from one color to the next so fast. I wanted to use the same velocity (rate of change) principle from the line width experiment but apply it to color, and have it meander aimlessly among all colors. I created a color object to store a value for each of the RGB color values, and then had each element of the color change independently. I didn’t want to complicate my loop function so I made a new function that is called from loop that steps along to a color which should be pretty close to the previous color. I enjoy the range, but as I expected it was a bit much, or too many colors at once, also the step is a bit too fast at times it seems.

02 Color, play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-02-color.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

actionscript source code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();

ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);

var div:Number = .1;

var ax:Number = 0;
var ay:Number = 0;

var line_max_width:Number = 50;
var line_min_width:Number = 0;
var line_width:Number = Math.random() * line_max_width;
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

var colors:Object = new Object();
colors.r = 0;
colors.g = 0;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;

function loop () {
ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;

line_width_velocity += Math.random() * 6 – 3;
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }

color_step();

this.graphics.lineStyle(line_width, rgb2hex(colors.r, colors.g, colors.b), 1);
this.graphics.lineTo(ball.x, ball.y);
}

setInterval(loop, 1000/30);

function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += Math.random() * 20 – 10; colors.r += colors.rv; colors.rv *= dampen; if (colors.r > 255) {
colors.r = 255;
} else if (colors.r < 0){ colors.r = 0; } colors.gv += Math.random() * 20 – 10; colors.g += colors.gv; colors.gv *= dampen; if (colors.g > 255) {
colors.g = 255;
} else if (colors.g < 0){ colors.g = 0; } colors.bv += Math.random() * 20 – 10; colors.b += colors.bv; colors.bv *= dampen; if (colors.b > 255) {
colors.b = 255;
} else if (colors.b < 0){
colors.b = 0;
}
}
[/cc]

Download

View the swf and get the fla here

Interactive Generative Flash Art Series – 00 – Line Width

After seeing the source code in the original experiment, I found myself wanting to play with the code. I saw many elements of the lines and actions that could be interesting to explore. This is the first in a series, of experiments I’ll post starting from this code and pushing different things each time. They’ll start slow and simple, like this one. All I’m doing is adding a few lines of code. The first thing I wanted to see from the original was a more gradual step in the width of the line. Here are a few screenshots from this iteration:

gen-art-00-line-width-1gen-art-00-line-width-2gen-art-00-line-width-3

Play here

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-00″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/01/gen-art-00-line-width.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

Source Code

[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);

var div:Number = .1;
var ax:Number = 0;
var ay:Number = 0;

var line_max_width:Number = 30;
var line_min_width:Number = 0;
var line_width:Number = Math.random() * line_max_width;
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;

function loop () {
ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;

line_width_velocity += Math.random() * 4 – 2;
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }
this.graphics.lineStyle(line_width, 0, 1);
this.graphics.lineTo(ball.x, ball.y);
}

setInterval(loop, 1000/30);
[/cc]

Method Explained

If you need a little walk through on my method to achieve this, all I did was create a variable to hold my line width, and the line width velocity (or rate of change). Every frame the line velocity grows or shrinks randomly and is applied to the line width variable. I apply a dampen to the velocity so it doesn’t get too out of hand and then set some limits to the line width. Pretty simple and it applies the same method of applying velocity to an object to make it move, but this velocity is being applied to a property of the object (width) that may not be as obvious as position. This still gives an effect of random width to the lines, but they are randomly widening and thinning, rather than just having random widths. It gives it a more fluid appearance. Any other ways you would use to achieve the same effect?

Download

Here’s the swf in action as well as the fla.

Interactive Generative Flash Art Series Intro

The world has been excited by html5/css3 recently and has been pushing limits and experimenting. It’s been exciting and funny at the same time – most of the things that are amazing people in html5 experiments have been done 5 years ago in flash. I’ve enjoyed it so much though because it has brought me back to what made me fall for flash initially: sites like levitated.net and yugop.com. People that wrote books about programming actionscript like Keith Peters, Jim Bumgardener Colin Moock, Robert Penner etc… and then art by people like Erik Natzke. I’m a geek and these guys are some of my heros (and don’t think that list is exhausted, I’ve got plenty of unmentioned flash heros), but not just because they could/can do what they do, but because they selflessly (open source-ly) taught me how to do some of it. The magic of creating something so engaging, responsive, animated, unique, random. Little experiments that feel like they contain so much life and are so lightweight -easily less than 10,240 bytes (read 10kb). I knew in high school trig and calculus that those formulas had power, but seeing it unfold and interact with it really is magical to me.

ball-natzke-1ball-natzke-2ball-natzke-3

A little inspiration

So, I’ve been toying with a lot of the things that actually taught me (or at least pushed me to learn) the basics of programming. With the years experience under my belt now I’m understanding it on a totally different level and all I want to do is find more things to make balls and lines bounce, move and swirl. And I also want to share it. Well, I recently stumbled upon a flash sneak peak video by Erik Natzke about some of his technique and then his open source files and really had some fun. Anyways I wanted to share some of the experiments that came from it. Let me know your thoughts and download the code and play with it. Let me know what else you come up with and share what you learn. I’ll start this series with a post of the original experiment from Erik on his blog here, Flash Code 101.

Natzke’s Flash Code 101

[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”alt-ball-natzke” movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/01/ball-natzke.swf” width=”550″ height=”550″ targetclass=”flashmovie”]

Please visit the blog article to view this interactive flash content. Flash plug-in required: Get Adobe Flash player

[/kml_flashembed]

If it looks like greek to you, I’d suggest going to Keith Peter’s tutorials (especially the first few on gravity, easing and elasticity).

Actionscript 3

For something so fun, it’s amazing that it’s barely over a dozen lines of code.
[cc lang=”actionscript”]
var Ball:Sprite = new Sprite();
Ball.graphics.beginFill(0x333333, 1);
Ball.graphics.drawCircle(0, 0, 30);
Ball.graphics.endFill();
addChild(Ball);

var div:Number = .1;
var ax:Number = 0;
var ay:Number = 0;

function loop () {
Ball.x -= ax = (ax + (Ball.x – mouseX) * div) * .9;
Ball.y -= ay = (ay + (Ball.y – mouseY) * div) * .9;
this.graphics.lineStyle(Math.random()*10, 0, 1);
this.graphics.lineTo(Ball.x, Ball.y);
}

setInterval(loop, 1000/30);
[/cc]

Here’s the swf in action, or download the fla to play (if you really would rather download a file than copy 15 lines of code).

Resolution

Well, I’ll be playing with this code and others and posting the experiments with some screenshots of what I create get’s created.

Access the html page URL and swf path from flash with as3

To get the url of the html page that contains the flash/swf file we need a little help from the browser. I’ve written about the following methods before, but they were in as2 with “Get current url to Flash swf using an External Interface call” and “Get Current URL and Query String Parameters to Flash in as2“. In as3, we’ll still need access to javascript in the form of ExternalInterface, so if you want to do this on a site that doesn’t allow javascript you’ll have to keep searching (or jump to the bottom for an alternative method). We don’t need to do anything with the javascript or have access to the pages source code, javascript just has to be enabled, and it works in every browser I have access to. All we do is call a javascript line from within the swf which gets the url in the browser, namely:
window.location.href
That is the javascript we need to call. But we do it from an externalInterface call like so:
ExternalInterface.call("window.location.href.toString")
or to make sure all browsers play nicely we can wrap it in a function in case the browser doesn’t want to execute that as a line, this seems to work more solidly:
ExternalInterface.call("function(){ return window.location.href.toString();}")
also note that we’re specifically applying the toString method, this is needed so the javascript actually executes something and can return it.

Other things you may want to do related to this is getting the query string variables form the url, which also uses externalInterface. You can also use this same method to get the domain, path, protocol, and even referrer. You could use some nice regex or substrings to find these from the full url, but it is already accessible. I can see a potential need for the speed to get the full url and then use internal code to cut it however I need it. But, I’m not convinced that using an external interface call takes that much time (but it’d be an interesting experiment to say the least).

You may want to find the url to the actual swf, and this doesn’t require javascript at all, the swf does know where it is even if it doesn’t know where it is embedded. We can use the loderInfo object and the url property. This returns the url to the swf file regardless of what page or even domain it is embedded on:
this.loaderInfo.url

For ExternalInterface to work in IE you need valid classid and id attributes in the tag. This is one of the reasons I use swfobject to handle my embed codes. It takes care of the Internet Exploder.

If your set up fails it may be because it throws a security error. To solve this to set the param allowScriptAccess to ‘always’ and in your actionscript add your domain, in order to enable the use of ExternalInterface.

[cc lang=”html”]

[/cc]
[cc lang=”actionscript”]
flash.system.Security.allowDomain(sourceDomain)
[/cc]

DEMO

get href url tutorial demo
This demo, gets all of the above mentioned values/properties and more. I threw in what I could think of that may be useful or interesting. It shows a couple ways to get the window location href as well as a way it won’t work. Then there are the rest of the properties available using this same method: href, host, hostname, hash (anchor link ‘#’), pathname (url after the domain), port, protocol, search (query string values), the document title and even referrer. Then from the loaderInfo object we can access the url of the swf as well as other things but most used is the bytesTotal and bytesLoaded. Now check out the demo here (adding an fpo hash and query string to the link just for demonstration purposes, feel free to play with the url and see the values updated.
[cc lang=”actionscript”]
import flash.external.ExternalInterface;

displayText.appendText(‘ExternalInterface.call(“function(){ return document.location.href.toString();}”): ‘ + ExternalInterface.call(“function(){ return document.location.href.toString();}”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“function(){ return window.location.href.toString();}”): ‘ + ExternalInterface.call(“function(){ return window.location.href.toString();}”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.href.toString”): ‘ + ExternalInterface.call(“window.location.href.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.href”): ‘ + ExternalInterface.call(“window.location.href”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.host.toString”): ‘ + ExternalInterface.call(“window.location.host.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.hostname.toString”): ‘ + ExternalInterface.call(“window.location.hostname.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.hash.toString”): ‘ + ExternalInterface.call(“window.location.hash.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.pathname.toString”): ‘ + ExternalInterface.call(“window.location.pathname.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.port.toString”): ‘ + ExternalInterface.call(“window.location.port.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.protocol.toString”): ‘ + ExternalInterface.call(“window.location.protocol.toString”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“window.location.search.toString”): ‘ + ExternalInterface.call(“window.location.search.toString”) + “\n”);

displayText.appendText(‘ExternalInterface.call(“function(){ return document.title;}”): ‘ + ExternalInterface.call(“function(){ return document.title;}”) + “\n”);
displayText.appendText(‘ExternalInterface.call(“function(){ return document.referrer;}”): ‘ + ExternalInterface.call(“function(){ return document.referrer;}”) + “\n”);

displayText.appendText(‘this.loaderInfo.url: ‘ + this.loaderInfo.url + “\n”);
displayText.appendText(‘this.loaderInfo.bytesLoaded: ‘ + this.loaderInfo.bytesLoaded + “\n”);
displayText.appendText(‘this.loaderInfo.bytesTotal: ‘ + this.loaderInfo.bytesTotal + “\n”);
[/cc]

Finally a method I’ve used in my video players when I want users to be able to share the link through the player is send an explicit ‘permalink’ in the flashvars or xml playlist. Then the video can be embedded on any site and users can share the original video url. Plus then I don’t have to rely on javascript. I’ve written about flashvars in the past though, so I’ll leave it to you to put 2 and 2 together. Flashvars is one more plug for swfobject to me though, because it makes it so I only have to declare them once and it handles all the browser specific code.

Anyways, this demo has been tested in mac firefox, chrome, safari and windows ie7, ie8, firefox and chrome. If you have a different browser please comment that it works (or not) so we can get a full spectrum, thanks!

Download Source Files

Related tools/resources: