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 Physics Animations Javascript Canvas 02

Adding more circles, each a multiple of the first circle’s coordinates. I like the effect of having them all move in unison. Ceck the source: interactive physics animations via javascript & canvas | 02

[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 = width / 2;
y = height / 2;
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]

Interactive Physics Animations Javascript Canvas 01

Adding a second circle, always at twice the x and y as the first. The first is still draggable. View the source: interactive physics animations via javascript & canvas | 01

[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 = width / 2;
y = height / 2;
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.fill(); } }); [/cc]

Interactive Javascript Canvas 00

I’ve played a lot with physics experiments in flash and moving more to javascript and canvas for simple things I wanted to test it out with some physics and animations. I’ve been curious to find out how the performance compares. Obviously this will depend on the browser, but the browsers that do support canvas should be able to handle some interactive physics animations.

I have this project I keep coming back to, it’s been in as2 and then in as3 and has have multiple faces. But the gist is there are a bunch of circles or balls and they float around in a specified area. There are physics “controls” exposed to the user and they can control the velocity of the balls, the gravity, air friction or drag, elasticity and they can even grab a ball and throw it across the stage (canvas). Here are a couple iterations of this: BFA Portfolio, Current Interactive POG Portfolio, Dribbble likes, Lastfm scrobbles.

I’m going to rebuild the basic functionality via javascript. I have had this on my list of things to explore for months now, in fact, ever since I saw Keith Peters go through his month long javascript exploration, he had a specific example that made me think I really needed to do it. I started and then life happened… But now I’m ready to start documenting my progress and trying to share what I’ve learned.

I’ll start with his initial example he titles JavaScript Day 27: Mouse Part II.
View my version here: interactive physics animations via javascript & canvas.

[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 = width / 2;
y = height / 2;
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.fill(); } }); [/cc]

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’

A More Interactive Portfolio

I think a portfolio is something that should be very interactive and intuitive. Check out what that has led to: circlecube’s interactive pog portfolio. I’ve been toying with trying to get something that was fun to look at, but also showed some work. Here is a first look at my Interactive portfolio of work which includes physics simulations and many options to play with the presentation of the body of work. Showing it to a friend he said it made him think of pogs (since the thumbnails are round and moving everywhere).

Well, enough, I’ll let you see what you see… Interactive POG Portfolio

The details

Well, if you’re interested, this is the same portfolio that is listed statically on my website. That’s because I’m using amfphp to read my wordpress database and get the custom post type of portfolio and access all the tags, images and details of each portfolio item. I’m using TweenNano from greensock for some of the motion but all the physics is coded in as3. I’m using the slider and switch from Nick Jonas.

Enjoy playing with the settings!

Now I’m thinking of other ways to implement it: specifically hooking into API services like last.fm, dribbble or twitter. Or rebuild it with jQuery and html5!

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