Dead Code Preservation :: Archived AS3 works from wonderfl.net

AnimalTail

ゆらゆら揺れる尻尾です。

自由形状の軟体を画像から生成することができます。
外形は荒いですが、それっぽく見えると思います。
影をつけている処理が意外に重く、これを外せばもっとまともになるかも。

今のところ用意している画像は4種類です。
Get Adobe Flash player
by tail_y 03 Dec 2009
/**
 * Copyright tail_y ( http://wonderfl.net/user/tail_y )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/z63v
 */

package
{
	/*
	  ゆらゆら揺れる尻尾です。
	  
	  自由形状の軟体を画像から生成することができます。
	  外形は荒いですが、それっぽく見えると思います。
	  影をつけている処理が意外に重く、これを外せばもっとまともになるかも。
	  
	  今のところ用意している画像は4種類です。
	 */	
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.display.StageQuality;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.events.MouseEvent;
	
	import net.hires.debug.Stats;

	public class AnimalTail extends Sprite
	{
		private var _main:AnimalTailMain;
		private var _count:int = int(Math.random()*10);
		private var _nextButton:TextField;
		
		public function AnimalTail()
		{
			addEventListener(Event.ADDED_TO_STAGE, init);	// flexBuilderとの互換性。
			Wonderfl.capture_delay(10);
		}
		
		private function init(event:Event):void {	// ここから開始
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// SWF設定
			stage.frameRate = 20;
			stage.quality = StageQuality.LOW;
			
			createNew(null);
			
			_nextButton = new TextField();
			_nextButton.background = true;
			_nextButton.text = " next ";
			_nextButton.borderColor = 0xffffff;
			_nextButton.autoSize = TextFieldAutoSize.LEFT;
			_nextButton.selectable = false;
			_nextButton.addEventListener(MouseEvent.CLICK, createNew);
			_nextButton.x = 465 - _nextButton.width;
			addChild(_nextButton);
			//addChild(new Stats());
		}
		private function createNew(event:Event):void{
			if (_main != null){
				_main.end();
				removeChild(_main);
				_main = null;
			}
			_main = new AnimalTailMain();
			addChildAt(_main, 0);
			_main.init(_count++);
		}
	}
}
















	import flash.display.Sprite;
	import flash.display.BitmapData;
	import __AS3__.vec.Vector;
	import flash.display.Bitmap;
	import flash.display.Graphics;
	import flash.geom.Rectangle;
	import flash.geom.Point;
	import flash.display.TriangleCulling;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.geom.Matrix;
	import flash.display.GradientType;
	import flash.display.BitmapDataChannel;
	import flash.system.Security;
	import flash.net.URLLoader;
	import flash.display.DisplayObject;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.GradientType;
	import flash.display.Sprite;
	import flash.display.StageQuality;
	import flash.events.Event;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.filters.BevelFilter;
	import flash.filters.BitmapFilterQuality;



class AnimalTailMain extends Sprite
{
	public static const STAGE_W:uint = 465;
	public static const STAGE_H:uint = 465;
	public static const GROUND_H:uint = 350;
	
	private var _loadUrl:String;
	private var _bevelColor:int;
	
	private var _sorceBitmapData:BitmapData;
	private var _puyoIllust:PuyoIllust;
	private var _planeShadow:PlaneShadow;
	
	private var _IMAGE_LIST:Array = [
						{url:"http://asset.sipo.jp/wonderfl/tail/tail1.png", shadow:0x996633},
						{url:"http://asset.sipo.jp/wonderfl/tail/tail2.png", shadow:0x000033},
						{url:"http://asset.sipo.jp/wonderfl/tail/tail3.png", shadow:0x000000},
						{url:"http://asset.sipo.jp/wonderfl/tail/tail4.png", shadow:0x000000},
						];
	
	public function init(count:int):void {	// ここから開始
		addEventListener(Event.ENTER_FRAME, frame);
		
		count %= _IMAGE_LIST.length;
		
		Security.loadPolicyFile("http://asset.sipo.jp/wonderfl/crossdomain.xml");
		_loadUrl = _IMAGE_LIST[count]["url"];
		_bevelColor = _IMAGE_LIST[count]["shadow"];
		
		var urlLoader:URLLoader = new URLLoader();
		urlLoader.addEventListener(Event.COMPLETE, urlLoadEnd);
		urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
		trace("loadStart");
		urlLoader.load(new URLRequest(_loadUrl));
	}
	// ByteArray(URLLoader(event.target).data)
	private function urlLoadEnd(event:Event):void{
		var loader:Loader = new Loader();
		loader.contentLoaderInfo.addEventListener(Event.COMPLETE, bynaryLoadEnd);
		loader.loadBytes(URLLoader(event.target).data);
	}
	private function bynaryLoadEnd(event:Event):void{
		var displayObject:DisplayObject = LoaderInfo(event.target).content;
		_sorceBitmapData = Bitmap(displayObject).bitmapData;
		trace("loadEnd");
		var topColor:int = 0xffffff;
		if (!_sorceBitmapData.transparent){	// 透過でない場合
			//var topColor:int = getSideTopColor(_sorceBitmapData);
			var w:int = _sorceBitmapData.width;
			var h:int = _sorceBitmapData.height;
			var transBitmapData:BitmapData = new BitmapData(w, h, true, 0x00000000);
			transBitmapData.threshold(_sorceBitmapData, new Rectangle(0, 0, w, h), new Point(),
										"==", topColor, 0x00000000, 0xFFFFFF, true);
			_sorceBitmapData = transBitmapData;
		}
		addChild(createBg(topColor));
		createPlaneShadow();
		createPuyoIllust();
	}
	private function createBg(color:uint):Bitmap{
		var bg:Bitmap = new Bitmap();
		bg.bitmapData = new BitmapData(STAGE_W, STAGE_H, false, color);
		var coverGradient:Sprite = new Sprite();
		var matrix:Matrix = new Matrix()
		matrix.createGradientBox(STAGE_W, STAGE_H, Math.PI / 2, 0, 0)
		coverGradient.graphics.beginGradientFill(GradientType.LINEAR, [0x000000, 0xffffff], [0.1, 0.1], [0, 230], matrix);
		coverGradient.graphics.drawRect(0, 0, STAGE_W, STAGE_H);
		bg.bitmapData.draw(coverGradient);
		return bg;
	}
	// 影を作る
	private function createPlaneShadow():void{
		_planeShadow = new PlaneShadow(STAGE_W, GROUND_H, 0.4, -0.2, 0.2, 24, 1);
		_planeShadow.y = 210;
		addChild(_planeShadow);
	}
	
	// プヨイラストを作る
	private function createPuyoIllust():void{
		_puyoIllust = new PuyoIllust();
		//_puyoIllust.setDebugDisplay(true);
		_puyoIllust.setPhisical(
					3,	//	derivation:int = 2
					0.5, 0.1,	//	verticalRate:Number = 0.3, rotateRate:Number = 0.2, 
					0.2, 0.03,	//	gravity:Number = 0.25, mousePower:Number = 0.1,
					0.90, 0.95,	//	friction:Number = 0.95, rFriction:Number = 0.92, 
					20, Math.PI/2	//	maxV:Number = 30, maxVR:Number = Math.PI):
					);
		addChild(_puyoIllust);
		_puyoIllust.first(_sorceBitmapData, STAGE_W, GROUND_H, 300, 12);
		_puyoIllust.filters = [new BevelFilter(5, 100, 0x000000, 0, _bevelColor, 1, 30, 30, 2, BitmapFilterQuality.MEDIUM)]
	}
	private function frame(event:Event):void{
		if (_puyoIllust != null) _puyoIllust.frame();
		if (_planeShadow != null) _planeShadow.frame(_puyoIllust.getDisplayBitmapData());
	}
	
	public function end():void{
		removeEventListener(Event.ENTER_FRAME, frame);
		_puyoIllust.end();
	}
}

class PuyoIllust extends Sprite
{
	private var _debugDisplay:Boolean;
	
	private var _sorceBitmap:BitmapData;
	private var _baseBitmap:BitmapData;
	private var _clear:BitmapData;
	private var _dragSprite:Vector.<Sprite> = new Vector.<Sprite>();
	
	private var _display:BitmapData;
	private var _displaySprite:Sprite;
	
	private var _point:Point = new Point();
	private var _rect:Rectangle;
	
	private var _baseSize:int;
	private var _stageWidth:int;
	private var _stageHeight:int;
	private var _blockSize:int;
	private var _blockNum:int;
	private var _dotNum:int;
	
	// 各種物理設定
	private var _derivation:int;	// 計算分割数
	private var _verticalRate:Number;	// 垂直方向ばね定数
	private var _rotateRate:Number;	// 回転方向ばね定数
	private var _gravity:Number;
	private var _mousePower:Number;
	private var _friction:Number;
	private var _rFriction:Number;
	private var _maxV:Number;
	private var _maxVR:Number;
	
	// 角度定数
	private static const _PI:Number = Math.PI;
	private static const _PI2:Number = 2 * _PI;
	private static const _R_90:Number	= _PI * 0.5;
	private static const _R_180:Number	= _PI * 1.0;
	private static const _R_270:Number	= _PI * -0.5;
	
	// ドットの個別データ。高速化のため、クラスにしない
	private var _dotX:Vector.<Number> = new Vector.<Number>();
	private var _dotY:Vector.<Number> = new Vector.<Number>();
	private var _dotR:Vector.<Number> = new Vector.<Number>();
	private var _dotVX:Vector.<Number> = new Vector.<Number>();
	private var _dotVY:Vector.<Number> = new Vector.<Number>();
	private var _dotVR:Vector.<Number> = new Vector.<Number>();
	private var _dotIs:Vector.<Boolean> = new Vector.<Boolean>();
	private var _dotLock:Vector.<Boolean> = new Vector.<Boolean>();
	private var _connectX:Vector.<Boolean> = new Vector.<Boolean>();
	private var _connectY:Vector.<Boolean> = new Vector.<Boolean>();
	private var _connectXX:Vector.<Boolean> = new Vector.<Boolean>();
	private var _connectYY:Vector.<Boolean> = new Vector.<Boolean>();
	
	// フリフリコンテンツ用
	private var _FURI_RATE:int = 50;
	private var _FURI_X:int = 10;
	private var _furiCount:int = 0;
	private var _furiIs:Boolean = true;
	private var _FURI_WAIT_MAX:int = 200;
	private var _furiWait:int = _FURI_WAIT_MAX;
	
	// ブロックのデータ
	private var _blockIs:Vector.<Boolean> = new Vector.<Boolean>();
	
	// 描画のデータ
	private var _vertices:Vector.<Number> = new Vector.<Number>();
	private var _indices:Vector.<int> = new Vector.<int>();
	private var _uvtData:Vector.<Number> = new Vector.<Number>();
	
	// 特定ポイント
	private var _dragTarget:int = -1;
	
	public function PuyoIllust():void{
		setDebugDisplay();
		setPhisical();
	}
	public function setDebugDisplay(debugDisplay:Boolean = false):void{
		_debugDisplay = debugDisplay;
	}
	public function setPhisical(derivation:int = 2,
								verticalRate:Number = 0.3, rotateRate:Number = 0.2, 
								gravity:Number = 0.25, mousePower:Number = 0.1,
								friction:Number = 0.95, rFriction:Number = 0.92, 
								maxV:Number = 30, maxVR:Number = Math.PI):void{
		_derivation = derivation;
		_verticalRate = verticalRate / derivation;
		_rotateRate = rotateRate / derivation;
		_gravity = gravity / derivation;
		_mousePower = mousePower / derivation;
		_friction = 1 - (1 - friction) / derivation;
		_rFriction = 1 - (1 - rFriction) / derivation;
		_maxV = maxV / derivation;
		_maxVR = maxVR / derivation;
	}
	public function first(baseBitmap:BitmapData,
						 stageWidth:int, stageHeight:int,
						 size:int, blockNum:int):void{
		
		var xi:int, yi:int;
		
		_baseSize = Math.max(baseBitmap.width, baseBitmap.height);
		_sorceBitmap = baseBitmap;
		_stageWidth = stageWidth;
		_stageHeight = stageHeight;
		_blockSize = int(size / blockNum);
		_blockNum = blockNum;
		_dotNum = _blockNum+1;
		_rect = new Rectangle(0, 0, _stageWidth, _stageHeight);
		
		// 正方形になおす
		var sorceWidth:int = _sorceBitmap.width;
		var sorceHeight:int = _sorceBitmap.height;
		_baseBitmap = new BitmapData(_baseSize, _baseSize, true, 0x00000000);
		_baseBitmap.copyPixels(_sorceBitmap, new Rectangle(0, 0, sorceWidth, sorceHeight), 
											new Point((_baseSize - sorceWidth)/2, (_baseSize - sorceHeight)/2));
		
		// bitmapの用意
		_clear = new BitmapData(_stageWidth, _stageHeight, true, 0x00000000)
		_display = new BitmapData(_stageWidth, _stageHeight, true, 0x00000000);
		var bitmap:Bitmap = new Bitmap(_display);
		addChild(bitmap);
		_displaySprite = new Sprite();
		
		
		
		// 初期位置(後で設定できるようにする?)
		var baseX:int = (_stageWidth - _blockSize*_blockNum) / 2;
		var baseY:int = 0;
		var index:int = 0;
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
				_dotX[index] = xi * _blockSize + baseX;
				_dotY[index] = yi * _blockSize + baseY;
				_dotR[index] = 0;
				_dotVX[index] = 0;
				_dotVY[index] = 0;
				_dotVR[index] = 0;
				_dotIs[index] = false;
				_dotLock[index] = false;
				_connectX[index] = false;
				_connectY[index] = false;
				_connectXX[index] = false;
				_connectYY[index] = false;
				_blockIs[index] = false;
				index++;
			}
		}
		
		// ブロックの状態を取得
		var baseBlockSize:Number = _baseSize / blockNum;
		var blockRectangle:Rectangle = new Rectangle(0, 0, baseBlockSize, baseBlockSize);
		var square:int = baseBlockSize*baseBlockSize;	// 面積
		for (xi = 0; xi < _blockNum; xi++){
			for (yi = 0; yi < _blockNum; yi++){
				blockRectangle.x = xi * baseBlockSize;
				blockRectangle.y = yi * baseBlockSize;
				var alphaHistogram:Vector.<Number> = _baseBitmap.histogram(blockRectangle)[3];
				if (alphaHistogram[0] != square){
					_dotIs[(xi + 0)*_dotNum + (yi + 0)] = true;
					_dotIs[(xi + 1)*_dotNum + (yi + 0)] = true;
					_dotIs[(xi + 0)*_dotNum + (yi + 1)] = true;
					_dotIs[(xi + 1)*_dotNum + (yi + 1)] = true;
					_blockIs[(xi + 0)*_dotNum + (yi + 0)] = true;
				}
			}
		}
		
		// ブロックの接続を設定
		index = 0;
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
				_connectX[index] = (xi < _dotNum - 1) && _dotIs[(xi + 1)*_dotNum + (yi + 0)];
				_connectY[index] = (yi < _dotNum - 1) && _dotIs[(xi + 0)*_dotNum + (yi + 1)];
				_connectXX[index] = (xi < _dotNum - 2) && _connectX[index] && _dotIs[(xi + 2)*_dotNum + (yi + 0)];
				_connectYY[index] = (yi < _dotNum - 2) && _connectY[index] && _dotIs[(xi + 0)*_dotNum + (yi + 2)];
				index++;
			}
		}
		// ドットのうち、ロックする物を選ぶ(ここをコメントアウトで、下に落ちる)
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < 1; yi++){
				_dotLock[xi*_dotNum + yi] = true;
			}
		}
		// 描画ベクターを作る
		createTraiangleVector();
		// ドラッグ用のスプライトを用意する
		createDragSprite();
		
		draw();
	}
	// 描画用データを用意する
	private function createTraiangleVector():void{
		var index:int = 0;
		var xi:int, yi:int;
		for (xi = 0; xi < _blockNum; xi++){
			for (yi = 0; yi < _blockNum; yi++){
				if (_blockIs[xi*_dotNum + yi]){
					_indices.push(xi*_dotNum + yi,		(xi+1)*_dotNum + yi,		xi*_dotNum + (yi+1));
					_indices.push((xi+1)*_dotNum + yi,	(xi+1)*_dotNum + (yi+1),	xi*_dotNum + (yi+1));
				}
			}
		}
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
					_uvtData[index++] = xi / _blockNum;
					_uvtData[index++] = yi / _blockNum;
			}
		}
	}
	// ドラッグするためのSpriteを用意する
	private function createDragSprite():void{
		for (var xi:int = 0; xi < _dotNum; xi++){
			for (var yi:int = 0; yi < _dotNum; yi++){
				if (_dotIs[xi*_dotNum + yi]){
					var sprite:Sprite = createCircleSprite(_blockSize, _debugDisplay ? 0.1 : 0);	// ドラッグ用の円形Sprite
					sprite.buttonMode = true;
					sprite.useHandCursor = true;
					sprite.addEventListener(MouseEvent.MOUSE_DOWN, dotMouseDown(xi*_dotNum + yi));
					//sprite.alpha = (xi*_dotNum + yi == 30) ? 1 : 0;
					_dragSprite.push(sprite);
					addChild(sprite);
				}else{
					_dragSprite.push(null);
				}
			}
		}
	}
	private function createCircleSprite(size:Number, alpha:Number):Sprite{
		var sprite:Sprite = new Sprite();
		var g:Graphics = sprite.graphics;
		g.beginFill(0x999900, alpha);
		g.drawCircle(0, 0, size);
		g.endFill();
		g.lineStyle(0, 0xff0000, alpha);
		g.moveTo(0, 0);
		g.lineTo(size*1.3, 0);
		return sprite;
	}
	private function dotMouseDown(index:int):Function{
		return function (event:Event):void{
			_dragTarget = index;
			stage.addEventListener(MouseEvent.MOUSE_UP, dotMouseUp);
			_furiIs = false;
		};
	}
	private function dotMouseUp(event:Event):void{
		_furiIs = true;
		_furiWait = _FURI_WAIT_MAX;
		
		_dragTarget = -1;
		stage.removeEventListener(MouseEvent.MOUSE_UP, dotMouseUp);
	}
	
	public function frame():void{
		for (var i:int = 0; i < _derivation; i++){
			rotate();	// 回転の計算
			foce();
			mouse();
			move();
		}
		draw();
	}
	// 回転させる
	private function rotate():void{
		var l:int = _dotNum;
		var index:int = 0, target:int;
		var dotVX:Number, dotVY:Number, dotVR:Number;
		var xi:int, yi:int;
		
		// 全体動作
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
				if (_dotIs[index]){
					if (_connectX[index]){	// 右パーティクルに対する処理
						target = (xi+1) * _dotNum + (yi);
						calcConnectRForce(index, target, 0);
						calcConnectRForce(target, index, _R_180);
					}
					if (_connectY[index]){	// 下パーティクルに対する処理
						target = (xi) * _dotNum + (yi+1);
						calcConnectRForce(index, target, _R_90);
						calcConnectRForce(target, index, _R_270);
					}
					if (_connectXX[index]){	// 右パーティクルに対する処理
						target = (xi+2) * _dotNum + (yi);
						calcConnectRForce(index, target, 0);
						calcConnectRForce(target, index, _R_180);
					}
					if (_connectYY[index]){	// 下パーティクルに対する処理
						target = (xi) * _dotNum + (yi+2);
						calcConnectRForce(index, target, _R_90);
						calcConnectRForce(target, index, _R_270);
					}
					// 摩擦
					_dotVR[index] *= _rFriction;
				}
				index++;
			}
		}
	}
	// 接続されたパーツの回転方向を計算する
	private function calcConnectRForce(main:int, target:int, connectAngle:Number):void{
		var angle:Number = Math.atan2(_dotY[target] - _dotY[main], _dotX[target] - _dotX[main]);
		_dotVR[main] += ajustRadian(angle - (connectAngle + _dotR[main])) * _rotateRate;
	}
	
	// 力をかける
	private function foce():void{
		var l:int = _dotNum;
		var index:int = 0, target:int;
		var dotVX:Number, dotVY:Number, dotVR:Number;
		var xi:int, yi:int;
		
		// 全体動作
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
				// バネ接続
				if (_dotIs[index]){
				
					if (_connectX[index]){	// 右パーティクルに対する処理
						target = (xi+1) * _dotNum + (yi);
						calcConnectFoce(index, target, 0, _blockSize);
						calcConnectFoce(target, index, _R_180, _blockSize);
					}
					if (_connectY[index]){	// 下パーティクルに対する処理
						target = (xi) * _dotNum + (yi+1);
						calcConnectFoce(index, target, _R_90, _blockSize);
						calcConnectFoce(target, index, _R_270, _blockSize);
					}
					if (_connectXX[index]){	// 右右パーティクルに対する処理
						target = (xi+2) * _dotNum + (yi);
						calcConnectFoce(index, target, 0, _blockSize*2);
						calcConnectFoce(target, index, _R_180, _blockSize*2);
					}
					if (_connectYY[index]){	// 下下パーティクルに対する処理
						target = (xi) * _dotNum + (yi+2);
						calcConnectFoce(index, target, _R_90, _blockSize*2);
						calcConnectFoce(target, index, _R_270, _blockSize*2);
					}
					dotVX = _dotVX[index];
					dotVY = _dotVY[index];
					dotVR = _dotVR[index];
					// 重力
					dotVY += _gravity;
					// 摩擦
					dotVX *= _friction;
					dotVY *= _friction;
					dotVR *= _rFriction;
					// 最大最小ロック
					dotVX =	(_maxV < dotVX) ? _maxV :
							(dotVX < -_maxV) ? -_maxV : dotVX;
					dotVY =	(_maxV < dotVY) ? _maxV :
							(dotVY < -_maxV) ? -_maxV : dotVY;
					dotVR = (_maxVR < dotVR) ? _maxVR :
							(dotVR < -_maxVR) ? -_maxVR : dotVR;
					_dotVX[index] = dotVX;
					_dotVY[index] = dotVY;
					_dotVR[index] = dotVR;
				}
				index++;
			}
		}
	}
	// 接続された2パーツの力を計算する
	private function calcConnectFoce(main:int, target:int, connectAngle:Number, distance:Number):void{
		var toAngle:Number = ajustRadian(connectAngle + _dotR[main]);	// あるべき角度
		var toX:Number = _dotX[main] + Math.cos(toAngle) * distance;
		var toY:Number = _dotY[main] + Math.sin(toAngle) * distance;
		var ax:Number = (_dotX[target] - toX) * _verticalRate;
		var ay:Number = (_dotY[target] - toY) * _verticalRate;
		_dotVX[main] += ax;
		_dotVY[main] += ay;
		_dotVX[target] -= ax;
		_dotVY[target] -= ay;
	}
	// radian角度を、-π~πの範囲に修正する
	private function ajustRadian(radian:Number):Number{
		return radian - _PI2 * Math.floor( 0.5 + radian / _PI2);
	}
	
	// マウス
	private function mouse():void{
		if (_dragTarget == -1) return;
		_dotVX[_dragTarget] = (mouseX - _dotX[_dragTarget])*_mousePower;
		_dotVY[_dragTarget] = (mouseY - _dotY[_dragTarget])*_mousePower;
	}
	// 移動
	private function move():void{
		if (_furiIs && _furiWait-- < 0){
			_furiCount = (_furiCount + 1) % _FURI_RATE;
		}
		var baseX:int = (_stageWidth - _blockSize*_blockNum) / 2 + _FURI_X * Math.sin(_PI2 * _furiCount / _FURI_RATE);
		
		var l:int = _dotNum;
		var index:int = 0;
		var dotX:Number, dotY:Number, dotR:Number;
		var xi:int, yi:int;
		for (xi = 0; xi < _dotNum; xi++){
			for (yi = 0; yi < _dotNum; yi++){
				if (_dotIs[index]){
					// 一時変数
					dotX = _dotX[index];
					dotY = _dotY[index];
					dotR = _dotR[index];
					// 加速の反映
					dotX += _dotVX[index];
					dotY += _dotVY[index];
					dotR += _dotVR[index];
					// 壁処理
					dotX =	(dotX < 0) ? 0 : 
							(_stageWidth < dotX) ? _stageWidth : 
							dotX;
					dotY = (_stageHeight < dotY) ? _stageHeight : dotY;
					
					_dragSprite[index].x = dotX;
					_dragSprite[index].y = dotY;
					
					if (_dotLock[index]){
						dotX = xi * _blockSize + baseX
						dotY = 0;
					}
					_dotX[index] = dotX;
					_dotY[index] = dotY;
					_dotR[index] = dotR;
				}
				index++;
			}
		}
		if (_debugDisplay) {
			index = 0;
			for (xi = 0; xi < _dotNum; xi++){
				for (yi = 0; yi < _dotNum; yi++){
					if (_dotIs[index]){
						_dragSprite[index].rotation = _dotR[index] * 180 / Math.PI;
						index++;
					}
				}
			}
		}
	}
	private function draw():void{
		_display.lock();
		var graphics:Graphics = _displaySprite.graphics;
		graphics.clear();
		var l:int = _dotNum;
		var index:int = 0;
		for (var xi:int = 0; xi < l; xi++){
			for (var yi:int = 0; yi < l; yi++){
				_vertices[index*2] = _dotX[index];
				_vertices[index*2+1] = _dotY[index];
				
				index++;
			}
		}
		graphics.beginBitmapFill(_baseBitmap);
		graphics.drawTriangles(_vertices, _indices, _uvtData);
		graphics.endFill();
		_display.copyPixels(_clear, _rect, _point);
		_display.draw(_displaySprite);
		_display.unlock();
	}
	
	public function getDisplayBitmapData():BitmapData{
		return _display;
	}
	
	public function end():void{
		stage.removeEventListener(MouseEvent.MOUSE_UP, dotMouseUp);
	}
}


class PlaneShadow extends Bitmap
{
	private var _width:int;
	private var _height:int;
	private var _minAlpha:Number;
	private var _maxAlpha:Number;
	private var _blur:BlurFilter;
	private var _clear:BitmapData;
	private var _black:BitmapData;
	private var _gradient:BitmapData;
	private var _alphaMap:BitmapData;
	private var _point:Point = new Point();
	private var _rect:Rectangle;
	
	public function PlaneShadow(width:int, height:int, heightRate:Number, minAlpha:Number, maxAlpha:Number, blur:int, quality:int){
		super();
		_width = width;
		_height = height;
		scaleY = heightRate;
		_minAlpha = minAlpha;
		_maxAlpha = maxAlpha;
		_blur = new BlurFilter(blur, blur, quality);
		_clear = new BitmapData(width, height, true, 0x00000000);
		bitmapData = _clear.clone();
		_alphaMap = new BitmapData(width, height, true, 0xffff0000);
		_black = new BitmapData(width, height, true, 0xff000000);
		_gradient = _clear.clone();
		createGradient();
		_rect = new Rectangle(0, 0, width, height);
		filters = [_blur];
	}
	private function createGradient():void{
		var coverGradient:Sprite = new Sprite();
		var matrix:Matrix = new Matrix()
		matrix.createGradientBox(_width, _height, Math.PI / 2, 0, 0)
		coverGradient.graphics.beginGradientFill(GradientType.LINEAR, [0x000000, 0x000000], [1-_minAlpha, 1-_maxAlpha], [0, 230], matrix);
		coverGradient.graphics.drawRect(0, 0, _width, _height);
		_gradient.draw(coverGradient);
	}
	public function frame(targetBitmapdata:BitmapData):void{
		bitmapData.lock();
		_alphaMap.copyChannel(targetBitmapdata, _rect, _point, BitmapDataChannel.ALPHA, BitmapDataChannel.RED);
		_alphaMap.copyPixels(_gradient, _rect, _point, null, null, true);
		bitmapData.copyChannel(_alphaMap, _rect, _point, BitmapDataChannel.RED, BitmapDataChannel.ALPHA);
		bitmapData.unlock();
	}
}