Beautifl - Flash Gallery

Thumbnail : Metaball with Phisycs Demo
Metaball with Phisycs Demo
clockmaker 2010-04-06 All rights reserved

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

/*
   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 = 50;
        public static const BT_WIDTH:uint = 50;
        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 = 22;
        
        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);
            _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));
    }
}