Blobs

Just kicking back with some good old fashioned Flash experimentation.


[kml_flashembed publishmethod=”static” fversion=”10.0.0″ movie=”http://www.bit-101.com/blog/wp-content/uploads/2009/08/Blobs.swf” width=”600″ height=”600″ targetclass=”flashmovie”]

Get Adobe Flash player

[/kml_flashembed]

Here’s the code:

[as]package
{
import com.bit101.components.CheckBox;
import com.bit101.components.Component;
import com.bit101.components.HUISlider;
import com.bit101.components.Knob;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;

[SWF(width=600, height=600, backgroundColor=0xdddddd, frameRate=31)]
public class Blobs extends Sprite
{
private var firm:Number;
private var firmSlider:HUISlider;

private var gravity:Number;
private var gravitySlider:HUISlider;

private var radius:Number;
private var radiusSlider:HUISlider;

private var rotate:Number;
private var rotationAmount:Number;
private var rotateKnob:Knob;

private var points:Array;
private var numPoints:int;

private var renderLinesCB:CheckBox;
private var renderLines:Boolean;

private var renderPointsCB:CheckBox;
private var renderPoints:Boolean;

private var renderOutlineSegments:Boolean;
private var renderOutlineSegmentsCB:CheckBox;

private var renderOutlineCurves:Boolean;
private var renderOutlineCurvesCB:CheckBox;

public function Blobs()
{
Component.initStage(stage);

points = new Array();
numPoints = 20;

firm = 0.05;
firmSlider = new HUISlider(this, 10, 10, “Firmness”, onFirmChange);
firmSlider.width = 580;
firmSlider.setSliderParams(0, .5, firm);
firmSlider.labelPrecision = 3;

gravity = 1.5;
gravitySlider = new HUISlider(this, 10, 22, “Gravity”, onGravityChange);
gravitySlider.width = 580;
gravitySlider.setSliderParams(0, 5, gravity);
gravitySlider.labelPrecision = 2;

radius = 100;
radiusSlider = new HUISlider(this, 10, 34, “Radius”, onRadiusChange);
radiusSlider.width = 580;
radiusSlider.setSliderParams(1, 250, radius);
radiusSlider.labelPrecision = 0;

renderPoints = true
renderPointsCB = new CheckBox(this, 10, 55, “Render Points”, onRenderPoints);
renderPointsCB.selected = true;

renderLines = true;
renderLinesCB = new CheckBox(this, 10, 70, “Render Lines”, onRenderLines);
renderLinesCB.selected = true;

renderOutlineSegments = true;
renderOutlineSegmentsCB = new CheckBox(this, 10, 85, “Render Outline Segments”, onRenderOutlineSegments);
renderOutlineSegmentsCB.selected = true;

renderOutlineCurves = false;
renderOutlineCurvesCB = new CheckBox(this, 10, 100, “Render Outline Curves”, onRenderOutlineCurves);
renderOutlineCurvesCB.selected = false;

rotate = 0;
rotationAmount = 0;
rotateKnob = new Knob(this, 250, 60, “Rotate”, onRotateChange);
rotateKnob.minimum = -.1;
rotateKnob.maximum = .1;
rotateKnob.value = 0;
rotateKnob.labelPrecision = 3;

for(var i:int = 0; i < numPoints; i++) { var angle:Number = Math.PI * 2 / numPoints * i; points.push(new Dot(400 + Math.cos(angle) * 100, 400 + Math.sin(angle) * 100)); } addEventListener(Event.ENTER_FRAME, enterFrameHandler); } private function onFirmChange(event:Event):void { firm = firmSlider.value; } private function onGravityChange(event:Event):void { gravity = gravitySlider.value; } private function onRadiusChange(event:Event):void { radius = radiusSlider.value; } private function onRotateChange(event:Event):void { rotationAmount = rotateKnob.value; } private function onRenderPoints(event:Event):void { renderPoints = renderPointsCB.selected; } private function onRenderLines(event:Event):void { renderLines = renderLinesCB.selected; } private function onRenderOutlineSegments(event:Event):void { renderOutlineSegments = renderOutlineSegmentsCB.selected; } private function onRenderOutlineCurves(event:Event):void { renderOutlineCurves = renderOutlineCurvesCB.selected; } private function enterFrameHandler(event:Event):void { graphics.clear(); var cx:Number = 0; var cy:Number = 0; for(var i:int = 0; i < numPoints; i++) { var point:Dot = points[i]; point.update(gravity); cx += point.x; cy += point.y; if(renderPoints) { graphics.beginFill(0); graphics.drawCircle(point.x, point.y, 2); graphics.endFill(); } } cx /= numPoints; cy /= numPoints; if(renderPoints) { graphics.beginFill(0xff0000); graphics.drawCircle(cx, cy, 5); graphics.endFill(); } for(i = 0; i < numPoints; i++) { var angle:Number = Math.PI * 2 / numPoints * i + rotate; var tx:Number = cx + Math.cos(angle) * radius; var ty:Number = cy + Math.sin(angle) * radius; point = points[i]; point.vx += (tx - point.x) * firm; point.vy += (ty - point.y) * firm; if(renderLines) { graphics.lineStyle(0, 0, .25); graphics.moveTo(cx, cy); graphics.lineTo(point.x, point.y); } if(renderOutlineSegments && i > 0)
{
graphics.lineStyle(0, 0x0000ff, 0.5);
graphics.moveTo(points[i – 1].x, points[i – 1].y);
graphics.lineTo(point.x, point.y);
}
}
if(renderOutlineSegments)
{
graphics.lineStyle(0, 0x0000ff, 0.25);
graphics.moveTo(points[i – 1].x, points[i – 1].y);
graphics.lineTo(points[0].x, points[0].y);
}
if(renderOutlineCurves)
{
renderCurves();
}
rotate += rotationAmount;
}

private function renderCurves():void
{
var mids:Array = new Array();
for(var i:int = 0; i < points.length - 1; i++) { mids[i] = new Point((points[i].x + points[i + 1].x) / 2, (points[i].y + points[i + 1].y) / 2); } mids[i] = new Point((points[i].x + points[0].x) / 2, (points[i].y + points[0].y) / 2); graphics.lineStyle(0, 0xff0000, .5); graphics.moveTo(mids[0].x, mids[0].y); for(i = 1; i < points.length; i++) { graphics.curveTo(points[i].x, points[i].y, mids[i].x, mids[i].y); } graphics.curveTo(points[0].x, points[0].y, mids[0].x, mids[0].y); } } }[/as] And you'll need this too: [as]package { public class Dot { public var x:Number; public var y:Number; public var vx:Number; public var vy:Number; public function Dot(x:Number, y:Number) { this.x = x; this.y = y; vx = Math.random() * 10 - 5; vy = Math.random() * 10 - 5; } public function update(gravity:Number):void { x += vx; y += vy; vy += gravity; if(x < 0) { x = 0; vx = 0; vy = 0; } if(x > 600)
{
x = 600;
vx = 0;
vy = 0;
}
if(y > 600)
{
y = 600;
vy = 0;
vx = 0;
}
vx *= .99;
vy *= .99;
}
}
}[/as]

And, if you want it to run as-is, you’ll need my minimal comps.

This entry was posted in ActionScript, Flash. Bookmark the permalink.

9 Responses to Blobs

  1. sascha/hdrs says:

    It’s good to have you back in AS land again! It was a hard and tough time for us all but now that you’re back things are getting back to positive again. ^_-

  2. nicoptere says:

    hi,
    glad to have you back to AS indeed ^^

    I think you can make your blob more robust by adding a second row of balls & sticks as described in this article : http://cowboyprogramming.com/2007/01/05/blob-physics/

  3. Julien says:

    Pretty cool !
    Now I remember why I subscribed to this blog in the first place.
    I kept reading though, don’t get me wrong 😉

  4. kp says:

    nicoptere, thanks for the link. interesting that I started out on a similar path.

  5. Cool.. and while trying to get it to walk up the walls, I managed to get a circle floating on the bottom right.. 😉

  6. Isak says:

    Wow, that is really cool.

  7. david says:

    I don’t like the knob. It doesn’t respond quite like I expect.

  8. dVyper says:

    Very nice. I played with it for quite a while 🙂

  9. Michael says:

    love it – really interesting how satisfying physics toys are to play with

Leave a Reply