/**
* Copyright jidolstar ( http://wonderfl.net/user/jidolstar )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/zPyr
*/
// forked from uwi's forked from: forked from: 渦巻
// forked from yd_niku's forked from: 渦巻
// forked from okoi's 渦巻
//
// 渦、台風っぽく
// 高速化しないと重いな
// ブラーもかけたいかも
// じっと見てると目をまわします
//
package {
import flash.accessibility.Accessibility;
import flash.display.*;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.BlurFilter;
import flash.geom.*;
import net.hires.debug.*;
[SWF(frameRate=60)]
/**
* 태풍 효과
* @author okoi
* @see http://wonderfl.net/code/d15a9c65440eaba3fb852462f61a521554282d74
*/
public class bitmap_typhoon extends Sprite {
private static const POWDER_NUM:int=3000;
private var _spire:Spire;
private var _container:Bitmap;
private var _firstPowder:Powder;
private var _canvas:BitmapData;
private var _filters:Array = [new BlurFilter(2, 2)]; //Blur 효과
private var _gain:ColorTransform = new ColorTransform(0.97, 0.97, 0.99, 1); //꼬리를 가지며 따라오는 효과. blue값이 더 큰것은 녹색 빛깔을 가지도록 하기 위해
public function bitmap_typhoon():void {
if (stage)
INIT();
else
addEventListener(Event.ADDED_TO_STAGE, INIT);
}
private function INIT(e:Event=null):void {
removeEventListener(Event.ADDED_TO_STAGE, INIT);
stage.scaleMode=StageScaleMode.NO_SCALE;
stage.align=StageAlign.TOP_LEFT;
// entry point
_spire=new Spire();
//태풍 효과를 출력할 영역
_container=new Bitmap();
_container.scaleX=_container.scaleY=2; //1px은 감질맛 나니깐 더 크게~ ^^
addChild(_container);
//메모리/frameRate 상태 표시
addChild(new Stats());
//cf)http://blog.jidolstar.com/656
if (stage.stageWidth > 0 && stage.stageHeight > 0) {
setup();
addEventHandler();
} else {
addEventListener(Event.ENTER_FRAME, function($e:Event):void {
if (stage.stageWidth > 0 && stage.stageHeight > 0) {
$e.target.removeEventListener($e.type, arguments.callee);
setup();
addEventHandler();
}
});
}
}
private function addEventHandler():void {
stage.addEventListener(Event.RESIZE, RESIZE);
addEventListener(Event.ENTER_FRAME, ENTER_FRAME);
stage.addEventListener(MouseEvent.MOUSE_DOWN, MOUSE_DOWN);
stage.addEventListener(MouseEvent.MOUSE_UP, MOUSE_UP);
}
private function setup():void {
_firstPowder=null;
var powder:Powder, pre:Powder;
var sw:Number=stage.stageWidth;
var sh:Number=stage.stageHeight;
//Powder 생성 및 최초 위치 지정
for (var i:int=0; i < POWDER_NUM; i++) {
var x:Number=Math.random() * sw;
var y:Number=Math.random() * sh;
powder=new Powder(x, y, int(Math.random() * 1000));
if (!_firstPowder) { //최초 Powder
_firstPowder=powder;
}
if (pre) { //링크드 리스트 연결
pre.next=powder;
}
pre=powder;
}
//비트맵 데이타 초기화
if (_canvas) {
_canvas.dispose();
_canvas=null;
}
_canvas=new BitmapData(sw >> 1, sh >> 1, false, 0);
_container.bitmapData=_canvas;
}
private function MOUSE_DOWN($e:MouseEvent):void {
Powder.speed=6;
}
private function MOUSE_UP($e:MouseEvent):void {
Powder.speed=1;
}
private function ENTER_FRAME(e:Event):void {
_spire.Update(stage.mouseX, stage.mouseY); //마우스 위치로 태풍의 중심 설정
//모든 Powder를 Spire에 지정된 위치를 중심으로 회전 이동
var powder:Powder=_firstPowder; //powders[0];
do {
powder.Move(_spire);
} while ((powder=powder.next) != null);
powder=_firstPowder; //powders[0];
var r:uint, g:uint, b:uint, c:uint;
var p:Point=new Point(), o:Point=p.clone();
_canvas.lock();
//_canvas.fillRect( _canvas.rect, 0x00 );
_canvas.colorTransform(_canvas.rect, _gain); //꼬리치며 따라오게~~ ^^
//canvas에 powder를 rendering한다.
do {
p.x=powder.posX >> 1;
p.y=powder.posY >> 1;
_canvas.setPixel(p.x, p.y, 0xffffff);
} while ((powder=powder.next) != null);
_canvas.applyFilter(_canvas, _canvas.rect, o, _filters[0]); //blur 적용
_canvas.unlock();
}
private function RESIZE(e:Event):void {
setup();
}
}
}
import flash.display.Stage;
/**
* 소용돌이 에너지
*/
class Spire {
public var centerX:int;
public var centerY:int;
public var rotatePower:Number=0.5;
public var cRotate:Number=Math.cos(rotatePower * Math.PI);
public var sRotate:Number=Math.sin(rotatePower * Math.PI);
/**
* 갱신
* @param _x
* @param _y
*/
public function Update(_x:int, _y:int):void {
centerX=_x;
centerY=_y;
}
}
/**
* 소용돌이 에너지의 희생이 되는 가루
*/
class Powder {
public var next:Powder; //다음 넘(링크드 리스트)
public var posX:Number; //현재 위치
public var posY:Number;
public var defX:Number; //최초 위치
public var defY:Number;
public var life:int; //생명주기
public var alpha:Number=0;
public static var speed:Number=1; //속도
public function Powder(_x:Number, _y:Number, _l:int) {
Set(_x, _y, _l);
}
public function Set(_x:Number, _y:Number, _l:int):void {
posX=_x;
posY=_y;
life=_l;
defX=_x;
defY=_y;
alpha=1;
}
public function Move(s:Spire):void {
var rnd:Number=(Math.random() - 0.5) * 2; //1px 내외로 흔들리는 효과를 위해 적용
var vecX:Number=(posX - s.centerX); //상대 X위치
var vecY:Number=(posY - s.centerY); //상대 Y위치
/*
//cos,sin은 비교적 비싼 비용을 지불해야한다. 그냥 사용하면 안좋음!
var theta : Number = (90 + s.rotatePower / 2) / 180 * Math.PI;
var cos : Number = Math.cos(theta);
var sin : Number = Math.sin(theta);
var vx : Number = vecX * cos + vecY * -sin;
var vy : Number = vecX * sin + vecY * cos;
*/
var vx:Number=vecX * s.cRotate + vecY * s.sRotate; //회전했을때 x값
var vy:Number=vecX * -s.sRotate + vecY * s.cRotate; //회전했을때 y값
var r:Number=Math.sqrt(vx * vx + vy * vy); //회전했을때 중심으로부터 거리
vx/=r; //cos
vy/=r; //sin
posX+=vx * 4 * speed + rnd; //4를 곱한건 약간 기울어져 있는 효과를 주기 위함
posY+=vy * 1 * speed + rnd;
life--;
//생명을 다하면 원래 태어났을때 위치로 이동, 생명주기 설정
if (life <= 0) {
posX=defX;
posY=defY;
life=1000 + Math.random() * 100; //생명주기
alpha=0;
}
//점점 밝아지면서 나타나도록
if (alpha < 1) {
alpha+=0.1;
}
}
}