Blobs, iteration 2

Worked on this some more…


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

Get Adobe Flash player

[/kml_flashembed]

[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.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 damp:Number;
private var dampSlider: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;

private var ball:Point;

public function Blobs()
{
Component.initStage(stage);
ball = new Point(150, 590);

points = new Array();
numPoints = 40;

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

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

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

damp = .99;
dampSlider = new HUISlider(this, 10, 46, “Damp”, onDampChange);
dampSlider.width = 580;
dampSlider.setSliderParams(.9, 1.0, damp);
dampSlider.labelPrecision = 3;

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

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

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

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

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) * radius, 400 + Math.sin(angle) * radius)); } 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 onDampChange(event:Event):void { damp = dampSlider.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); point.vx *= damp; point.vy *= damp; checkBall(point); 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();
}
graphics.lineStyle(0, 0, .5);
graphics.drawCircle(ball.x, ball.y, 40);
rotate += rotationAmount;
}

private function checkBall(point:Dot):void
{
var dx:Number = point.x – ball.x;
var dy:Number = point.y – ball.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
if(dist < 40) { point.x = ball.x + dx / dist * 40; point.y = ball.y + dy / dist * 40; point.vx = 0; point.vy = 0; } } 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.beginFill(0xff0000); 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); graphics.endFill(); } } }[/as] [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 = 0; vy = 0; } 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;
}
}
}
}[/as]

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

2 Responses to Blobs, iteration 2

  1. Rob says:

    Nice! Reminds me of an old (AS1) experiment of mine – http://rmd.com.au/files/labs/jellytri05.swf

    I think you’ve inspired me to update it to AS3.

  2. lm says:

    i think you should add one sublayer for more stable results
    like here http://cowboyprogramming.com/2007/01/05/blob-physics/

Leave a Reply