Interactive Physics Animations Javascript Canvas 08

Thus far, we’ve been doing lot of setup and it hasn’t been very visually exciting. Now we start the fun stuff! Adding motion! Before we just has a draw function, but now we’ll add a function that will control the animations and we’ll also need a way to execute code repeatedly over a period of time. We’ll use a setInterval function to call first update and then draw multiple times a second and this will give the essence of animation! Here we’re just adjusting the coordinates of each of the dots every time the update function is fired, which happens to be every 100 milliseconds, or 10 times a second. interactive physics animations via javascript & canvas | 08.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;
var total_dots = 25;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();
var drag_i = -1;

var this_dot = {};
for (var i=0; i < total_dots; i++){ var this_dot = { x: Math.random()*canvas.width, y: Math.random()*canvas.height, width:canvas.width, height: canvas.height, radius:Math.random()*20+10 }; dots.push(this_dot); } draw(); $("#canvas").mousedown(function (event) { var dx, dy, dist; for (var i=0; i < dots.length; i++){ dx = event.pageX - this.offsetLeft - dots[i].x; dy = event.pageY - this.offsetTop - dots[i].y; dist = Math.sqrt(dx * dx + dy * dy); if(dist < radius) { drag = true; drag_i = i clickX = dx; clickY = dy; continue; } } }); $("#canvas").mouseup(function (event) { drag = false; drag_i = -1; }); $("#canvas").mousemove(function (event) { if(drag) { dots[drag_i].x = event.pageX - this.offsetLeft - clickX; dots[drag_i].y = event.pageY - this.offsetTop - clickY; draw(); } }); function update(){ for (var i=0; i < dots.length; i++){ if (drag_i != i){ var this_dot = dots[i]; this_dot.x += Math.random() * 10 - 5; this_dot.y += Math.random() * 10 - 5; } } } function draw() { context.clearRect(0, 0, canvas.width, canvas.height); for (var i=0; i < dots.length; i++){ context.beginPath(); context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false); context.fill(); context.closePath(); } } setInterval(function() { update(); draw(); }, 100); }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 7b

Here’s an interesting rendering I found when I was playing with drawing multiple dots. interactive physics animations via javascript & canvas | 07 B.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;
var total_dots = 25;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();
var drag_i = -1;

var this_dot = {};
for (var i=0; i < total_dots; i++){ var this_dot = { x: Math.random()*canvas.width, y: Math.random()*canvas.height, width:canvas.width, height: canvas.height, radius:Math.random()*20+10 }; dots.push(this_dot); } draw(); $("#canvas").mousedown(function (event) { var dx, dy, dist; for (var i=0; i < dots.length; i++){ dx = event.pageX - this.offsetLeft - dots[i].x; dy = event.pageY - this.offsetTop - dots[i].y; dist = Math.sqrt(dx * dx + dy * dy); if(dist < radius) { drag = true; drag_i = i clickX = dx; clickY = dy; continue; } } }); $("#canvas").mouseup(function (event) { drag = false; drag_i = -1; }); $("#canvas").mousemove(function (event) { if(drag) { dots[drag_i].x = event.pageX - this.offsetLeft - clickX; dots[drag_i].y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, canvas.width, canvas.height); context.beginPath(); for (var i=0; i < dots.length; i++){ context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false); } context.fill(); } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 07

This step we’ll add a variable to hold the total number of dots we want to create and use it in our for loop that creates the dots. We’ll also give the dots a little more randomness by varying the size with a radius value. interactive physics animations via javascript & canvas | 07.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;
var total_dots = 25;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();
var drag_i = -1;

var this_dot = {};
for (var i=0; i < total_dots; i++){ var this_dot = { x: Math.random()*canvas.width, y: Math.random()*canvas.height, width:canvas.width, height: canvas.height, radius:Math.random()*20+10 }; dots.push(this_dot); } draw(); $("#canvas").mousedown(function (event) { var dx, dy, dist; for (var i=0; i < dots.length; i++){ dx = event.pageX - this.offsetLeft - dots[i].x; dy = event.pageY - this.offsetTop - dots[i].y; dist = Math.sqrt(dx * dx + dy * dy); if(dist < radius) { drag = true; drag_i = i clickX = dx; clickY = dy; continue; } } }); $("#canvas").mouseup(function (event) { drag = false; drag_i = -1; }); $("#canvas").mousemove(function (event) { if(drag) { dots[drag_i].x = event.pageX - this.offsetLeft - clickX; dots[drag_i].y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, canvas.width, canvas.height); for (var i=0; i < dots.length; i++){ context.beginPath(); context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false); context.fill(); context.closePath(); } } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 06

Here we’re going to get more into the interactive programming on these dots. We started with one dot that was draggable. This update applies a drag/drop code to each dot object with some logic to keep track of which dot is being dragged. This is quite a bit different than accomplishing the same thing in flash. Flash lets us have visual objects, but here in javascript we have all these objects and they are drawn on the stage/canvas every “frame”. The elements once drawn really don’t have any properties. So we’re attaching mousedown, mouseup and mousemove events to the canvas. In flash we would be applying a click event to the objects themselves. On mousedown we check coordinates to see if we’ve clicked on any of the dots. We also need a variable to store which one is being clicked or dragged at the moment, and this is pretty easy since we set up earlier to have an array holding all our dots, we’ll just use the index of that dot. With mousemove we drag the dot that’s been clicked using that index value, and then mouseup we drop it. interactive physics animations via javascript & canvas | 06.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();
var drag_i = -1;

var this_dot = {};
for (var i=0; i < 5; i++){ var this_dot = { x: Math.random()*canvas.width, y: Math.random()*canvas.height, width:canvas.width, height: canvas.height, radius:25}; dots.push(this_dot); } draw(); $("#canvas").mousedown(function (event) { var dx, dy, dist; for (var i=0; i < dots.length; i++){ dx = event.pageX - this.offsetLeft - dots[i].x; dy = event.pageY - this.offsetTop - dots[i].y; dist = Math.sqrt(dx * dx + dy * dy); if(dist < radius) { drag = true; drag_i = i clickX = dx; clickY = dy; continue; } } }); $("#canvas").mouseup(function (event) { drag = false; drag_i = -1; }); $("#canvas").mousemove(function (event) { if(drag) { dots[drag_i].x = event.pageX - this.offsetLeft - clickX; dots[drag_i].y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, canvas.width, canvas.height); for (var i=0; i < dots.length; i++){ context.beginPath(); context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false); context.fill(); context.closePath(); } } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 05

Now we’ll apply this object oriented programming to each dot and give them all random placement. interactive physics animations via javascript & canvas | 05.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
var dots = new Array();

var this_dot = {};
for (var i=0; i < 5; i++){ var this_dot = { x: Math.random()*canvas.width, y: Math.random()*canvas.height, width:canvas.width, height: canvas.height, radius:25}; dots.push(this_dot); } draw(); $("#canvas").mousedown(function (event) { var dx, dy, dist; dx = event.pageX - this.offsetLeft - this_dot.x; dy = event.pageY - this.offsetTop - this_dot.y; dist = Math.sqrt(dx * dx + dy * dy); if(dist < radius) { drag = true; clickX = dx; clickY = dy; } else { drag = false; } }); $("#canvas").mouseup(function (event) { drag = false; }); $("#canvas").mousemove(function (event) { if(drag) { this_dot.x = event.pageX - this.offsetLeft - clickX; this_dot.y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, canvas.width, canvas.height); for (var i=0; i < dots.length; i++){ context.beginPath(); context.arc(dots[i].x, dots[i].y, dots[i].radius, 0, Math.PI * 2, false); context.fill(); context.closePath(); } } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 04

This time we won’t make the canvas any different visually, it’s more just cleaning up the code. We’re making the circle into a dot object, then later it will be easier to keep track of it (and any others). interactive physics animations via javascript & canvas | 04.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);

var this_dot = {
x: Math.random()*canvas.width/5,
y: Math.random()*canvas.height/5,
width:canvas.width,
height: canvas.height,
radius:25};

draw();

$(“#canvas”).mousedown(function (event) {
var dx, dy, dist;
dx = event.pageX – this.offsetLeft – this_dot.x;
dy = event.pageY – this.offsetTop – this_dot.y;
dist = Math.sqrt(dx * dx + dy * dy);
if(dist < radius) { drag = true; clickX = dx; clickY = dy; } else { drag = false; } }); $("#canvas").mouseup(function (event) { drag = false; }); $("#canvas").mousemove(function (event) { if(drag) { this_dot.x = event.pageX - this.offsetLeft - clickX; this_dot.y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, canvas.width, canvas.height); context.beginPath(); context.arc(this_dot.x, this_dot.y, this_dot.radius, 0, Math.PI * 2, false); context.arc(this_dot.x*2, this_dot.y*2, this_dot.radius, 0, Math.PI * 2, false); context.arc(this_dot.x*3, this_dot.y*3, this_dot.radius, 0, Math.PI * 2, false); context.arc(this_dot.x*4, this_dot.y*4, this_dot.radius, 0, Math.PI * 2, false); context.arc(this_dot.x*5, this_dot.y*5, this_dot.radius, 0, Math.PI * 2, false); context.arc(this_dot.x*6, this_dot.y*6, this_dot.radius, 0, Math.PI * 2, false); context.fill(); } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Physics Animations Javascript Canvas 03

This iteration really isn’t that big, but I figured baby steps may be the way to go here. We’re just giving the first circle a random position. The other dots are positioned relative to the first one still. interactive physics animations via javascript & canvas | 03.

[cc lang=”javascript”]
$(function () {
var canvas, context, width, height, x, y, radius = 25, clickX, clickY, drag = false;

canvas = $(“#canvas”)[0];
context = canvas.getContext(“2d”);
width = canvas.width;
height = canvas.height;
x = Math.random()*canvas.width/5;
y = Math.random()*canvas.height/5;
draw();

$(“#canvas”).mousedown(function (event) {
var dx, dy, dist;
dx = event.pageX – this.offsetLeft – x;
dy = event.pageY – this.offsetTop – y;
dist = Math.sqrt(dx * dx + dy * dy);
if(dist < radius) { drag = true; clickX = dx; clickY = dy; } else { drag = false; } }); $("#canvas").mouseup(function (event) { drag = false; }); $("#canvas").mousemove(function (event) { if(drag) { x = event.pageX - this.offsetLeft - clickX; y = event.pageY - this.offsetTop - clickY; draw(); } }); function draw() { context.clearRect(0, 0, width, height); context.beginPath(); context.arc(x, y, radius, 0, Math.PI * 2, false); context.arc(x*2, y*2, radius, 0, Math.PI * 2, false); context.arc(x*3, y*3, radius, 0, Math.PI * 2, false); context.arc(x*4, y*4, radius, 0, Math.PI * 2, false); context.arc(x*5, y*5, radius, 0, Math.PI * 2, false); context.arc(x*6, y*6, radius, 0, Math.PI * 2, false); context.fill(); } }); [/cc]Follow the whole Interactive Physics Animations via Javascript & Canvas series.

Interactive Javascript Canvas Series

I’ve been playing with canvas and different javascript drawing libraries a lot lately in my projects at work. I’ve been antsy to play with the techniques I’ve learned and apply it to some more interactive experiments. Much like my last series on generative art in flash, but this will all be in javascript! In case you’re extra interested in this type of stuff, go check out Keith Peters’ month long exploration into javascript on his bit-101 site, he’s did some great stuff, and I learned a lot from that. I’m not going to sign up to post every day or anything, but I’ll keep it going for a while at least. So, stay tuned! And let me know if you’re really wanting to see this go into any specific directions.

Here goes nothin’

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.