Metaball
Simple Metaball
/**
* Copyright takumi0125 ( http://wonderfl.net/user/takumi0125 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/zscM
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.filters.BevelFilter;
import flash.filters.BitmapFilterType;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
[SWF(backgroundColor = 0xffffff, frameRate = 60)]
public class Main extends Sprite {
private var _circlesContainer:Sprite; //円を配置するSprite
private var _circles:Vector.<Shape>; //円を格納するVector
private var _circleParams:Vector.<Object>; //円の各値を格納するVector
private var _criclesBitmapData:BitmapData; //円を描画するBitmapData
private var _metaballsBitmap:Bitmap; //メタボールを描画するBitmap
private var _metaballsBitmapData:BitmapData; //メタボールを描画するBitmapData
private var _thresholdDestPoint:Point; //2階調化時に使用するPoint (0, 0)
private var _bitmapRect:Rectangle; //ビットマップの範囲
private var _bitmapDataWidth:Number; //ステージ (ビットマップ)の横幅
private var _bitmapDataHeight:Number; //ステージ (ビットマップ)の縦幅
private const _NUM_CIRCLES:uint = 50; //円の数
private const _CIRCLE_MOVE_STEP:uint = 10; //円の移動距離の基準値
private const _CIRCLE_RADIUS:Number = 60; //円の半径の基準値
private const _THRESHOLD:uint = 0xffffffff; //2階調化のしきい値
private const _BITMAP_SIZE_MARGIN:Number = 100; //ステージ端のフィルタ部分を切り取るためのマージン
//constructor
public function Main() {
_init();
}
//イニシャライズ
private function _init():void {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT
//円
_circlesContainer = new Sprite();
_circlesContainer.blendMode = BlendMode.ADD;
_circles = new Vector.<Shape>();
_circleParams = new Vector.<Object>();
var circle:Shape, radius:Number;
for(var i:uint = 0; i< _NUM_CIRCLES; i++) {
radius = Math.random() * _CIRCLE_RADIUS + _CIRCLE_RADIUS;
circle = _createCircleShape(radius);
_circles.push(circle);
_circlesContainer.addChild(circle);
circle.x = Math.random() * stage.stageWidth;
circle.y = Math.random() * stage.stageHeight;
_circleParams.push({ radius: radius, dx: Math.random() * _CIRCLE_MOVE_STEP - _CIRCLE_MOVE_STEP / 2, dy: Math.random() * _CIRCLE_MOVE_STEP - _CIRCLE_MOVE_STEP / 2 });
}
_thresholdDestPoint = new Point(0, 0);
//addChildするBitmapを生成
_metaballsBitmap = new Bitmap();
_metaballsBitmap.x = -(_BITMAP_SIZE_MARGIN >> 1);
_metaballsBitmap.y = -(_BITMAP_SIZE_MARGIN >> 1);
addChild(_metaballsBitmap);
//まずサイズを取得してBitmapDataを生成
_resizeHandler();
//リサイズ処理
stage.addEventListener(Event.RESIZE, _resizeHandler);
//フレームごとの処理
addEventListener(Event.ENTER_FRAME, _enterFrameHandler);
}
//円を生成
private function _createCircleShape(radius:Number):Shape {
var circle:Shape = new Shape();
var circleGraphics:Graphics;
var matrix:Matrix = new Matrix();
matrix.createGradientBox(radius * 2, radius * 2, 0, -radius, -radius);
circleGraphics = circle.graphics;
circleGraphics.beginGradientFill(GradientType.RADIAL, [ 0xffffff, 0x000000 ], [ 1, 0 ], [ 127, 255 ], matrix);
circleGraphics.drawCircle(0, 0, radius);
circleGraphics.endFill();
circle.blendMode = BlendMode.ADD;
return circle;
}
//BitmapDataを生成
private function _createBitmapData():void {
if(_criclesBitmapData) _criclesBitmapData.dispose();
_criclesBitmapData = new BitmapData(_bitmapDataWidth, _bitmapDataHeight, true, 0x00000000);
if(_metaballsBitmapData) _metaballsBitmapData.dispose();
_metaballsBitmapData = new BitmapData(_bitmapDataWidth, _bitmapDataHeight, true, 0x00000000);
_metaballsBitmap.bitmapData = _metaballsBitmapData;
}
//フレームごとの処理
private function _enterFrameHandler(e:Event = null):void {
var circle:Shape, circleParam:Object, radius:Number;
for(var i:uint = 0; i< _NUM_CIRCLES; i++) {
circle = _circles[i];
circleParam = _circleParams[i];
radius = circleParam.radius;
circle.x += circleParam.dx;
if(circle.x > _bitmapDataWidth + radius || circle.x < -radius) _circleParams[i].dx *= -1;
circle.y += circleParam.dy;
if(circle.y > _bitmapDataHeight + radius || circle.y < -radius) _circleParams[i].dy *= -1;
}
_criclesBitmapData.fillRect(_bitmapRect, 0x00000000);
_criclesBitmapData.draw(_circlesContainer);
_metaballsBitmapData.fillRect(_bitmapRect, 0xffaacf53);
_metaballsBitmapData.threshold(_criclesBitmapData, _bitmapRect, _thresholdDestPoint, "<", _THRESHOLD);
}
//リサイズ処理
private function _resizeHandler(e:Event = null):void {
_bitmapDataWidth = stage.stageWidth + _BITMAP_SIZE_MARGIN;
_bitmapDataHeight = stage.stageHeight + _BITMAP_SIZE_MARGIN;
_bitmapRect = new Rectangle(0, 0, _bitmapDataWidth, _bitmapDataHeight);
_createBitmapData();
}
}
}