forked from: Metaball with Phisycs Demo
Metaball with Phisycs Demo
Metaball, inspired by
http://wonderfl.net/code/0efe03ed94668754891f3a529f516c0ca8b33b29
QuickBox2D, thanks to
http://blog.alumican.net/2009/06/28_021753
// forked from clockmaker's Metaball with Phisycs Demo
/*
Metaball with Phisycs Demo
Metaball, inspired by
http://wonderfl.net/code/0efe03ed94668754891f3a529f516c0ca8b33b29
QuickBox2D, thanks to
http://blog.alumican.net/2009/06/28_021753
*/
package {
import com.actionsnippet.qbox.*;
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
import net.hires.debug.Stats;
[SWF(width=465, height=465, frameRate=60)]
/**
* LiquidDemo - Metaball + QuickBox2D -
* @author yasu
*/
public class LiquidDemo extends MovieClip {
public static const BT_HEIGHT:uint = 30;
public static const BT_WIDTH:uint = 30;
public static const QUICK_SCALE:uint = 30;
public static const STAGE_H:uint = 465;
public static const STAGE_W:uint = 465;
public static const TOTAL_BALL_COUNT:uint = 12;
public function LiquidDemo() {
stage.quality = StageQuality.MEDIUM;
_initQuickBox2D();
_initMetaball();
addChild(new Stats);
addEventListener(Event.ENTER_FRAME, _onEnterFrame);
}
private var _balls:Vector.<MetaBall>;
private var _bmd:BitmapData;
private var _bmp:Bitmap;
private var _quickObjs:Vector.<QuickObject>;
private var _radius:Vector.<int>;
private var _sim:QuickBox2D;
private function _convertRGBColor(pixelsValue:int):Number {
var r:Number = pixelsValue * 0.3;
var g:Number = pixelsValue * 0.3;
var b:Number = pixelsValue * 0.5;
r = ((r > 255) ? 255 : r) << 16;
g = ((g > 255) ? 255 : g) << 8;
b = ((b > 255) ? 255 : b);
return r | g | b;
}
private function _initMetaball():void {
_balls = new Vector.<MetaBall>(TOTAL_BALL_COUNT, true);
for (var i:uint = 0; i < TOTAL_BALL_COUNT; i++) {
var ball:MetaBall = new MetaBall(new Point(int(Utils.random(1, BT_WIDTH)), int(Utils.random(1, BT_HEIGHT))), _radius[ i ] * 300);
_balls[ i ] = ball;
}
_bmd = new BitmapData(BT_WIDTH, BT_HEIGHT, false, 0x000000);
_bmp = new Bitmap(_bmd, "never", true);
_bmp.width = STAGE_W;
_bmp.height = STAGE_H;
addChild(_bmp);
}
private function _initQuickBox2D():void {
_sim = new QuickBox2D(this as MovieClip);
_sim.createStageWalls();
_sim.setDefault({ friction: 0.025, restitution: 0.8 });
_quickObjs = new Vector.<QuickObject>(TOTAL_BALL_COUNT, true);
_radius = new Vector.<int>(TOTAL_BALL_COUNT, true);
for (var i:int = 0; i < TOTAL_BALL_COUNT; i++) {
_radius[ i ] = Utils.random(10, 30);
_quickObjs[ i ] = _sim.addCircle({
x: Math.random() * 465 / QUICK_SCALE,
y: Math.random() * 465 / QUICK_SCALE,
radius: _radius[ i ] / QUICK_SCALE })
}
_sim.start();
_sim.mouseDrag();
}
private function _onEnterFrame(evt:Event):void {
_sync();
for (var i:uint = 0; i < TOTAL_BALL_COUNT; i++)
_balls[ i ].update();
_render();
}
private function _render():void {
_bmd.lock();
for (var yy:uint = 0; yy < BT_HEIGHT; yy++) {
for (var xx:uint = 0; xx < BT_WIDTH; xx++) {
var pixelsValue:int = 0;
for (var i:uint = 0; i < TOTAL_BALL_COUNT; i++) {
var ball:MetaBall = _balls[ i ];
pixelsValue += ball.currentRadius / (1 + ball.getPixelValue(xx, yy));
}
_bmd.setPixel(xx, yy, _convertRGBColor(pixelsValue));
}
}
_bmd.unlock();
}
private function _sync():void {
for (var i:int = 0; i < TOTAL_BALL_COUNT; i++) {
_balls[ i ].position.x = _quickObjs[ i ].x * QUICK_SCALE * (BT_WIDTH / STAGE_W);
_balls[ i ].position.y = _quickObjs[ i ].y * QUICK_SCALE * (BT_HEIGHT / STAGE_H);
}
}
}
}
import flash.geom.Point;
class Utils {
/**
* Random value maker between min and max.
* @param min
* @param max
* @return random number
*/
public static function random(min:Number, max:Number):Number {
if (max == min) {
return max;
} else if (max < min) {
var _temp:Number = max;
max = min;
min = _temp;
}
return Math.random() * (max - min) + min;
}
}
class MetaBall {
public function MetaBall(pos:Point, radius:Number) {
position = pos;
currentRadius = radius;
}
public var currentRadius:uint;
public var position:Point;
private var _pixelsX:Vector.<int>;
private var _pixelsY:Vector.<int>;
public function getPixelValue(x:uint, y:uint):Number {
return _pixelsX[ x ] + _pixelsY[ y ];
}
public function update():void {
// set pixels
var w:int = LiquidDemo.BT_WIDTH;
var h:int = LiquidDemo.BT_HEIGHT;
_pixelsX = new Vector.<int>(w, true);
_pixelsY = new Vector.<int>(h, true)
for (var xx:uint = 0; xx < w; xx++)
_pixelsX[ xx ] = int((position.x - xx) * (position.x - xx));
for (var yy:uint = 0; yy < h; yy++)
_pixelsY[ yy ] = int((position.y - yy) * (position.y - yy));
}
}