package { import flash.display.Sprite; import flash.utils.setTimeout; [SWF(width=465, height=465, backgroundColor=0x00AEEF, frameRate=60)] public class Main extends Sprite { private static const TEXTCOLOR:uint = 0xffffff; private static const BGCOLOR:uint = 0x00AEEF; private static const LABEL_ARRAY:Array = ["HOME","ABOUT","WORKS","CONTACT"]; public function Main() { init(); } private function init():void { for(var i:int=0; i<4; i++) { var btn:SandButton = new SandButton(LABEL_ARRAY[i],48,TEXTCOLOR,BGCOLOR,false); btn.y = 40*i + 160; btn.x = 120; addChild(btn); setTimeout(btn.appearMotion, 40*(i+1)); } } } } import flash.display.Sprite; import flash.display.BitmapData; import flash.display.Bitmap; import flash.events.Event; import flash.events.MouseEvent; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; import flash.geom.Rectangle; import flash.geom.Point; import flash.filters.BlurFilter; class SandButton extends Sprite { private static const APPEAR_RANGE:Number = 100; private static const TAIL_LENGTH:Number = 30; private static const DISTANCE:Number = 500; private var bd:BitmapData; private var canvas:BitmapData; private var particles:Particle; private var pnum:uint = 0; private var _setup:Boolean; public function SandButton(buttonLabel:String, size:Number, textColor:uint, bgColor:uint, setup:Boolean) { _setup = setup; var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat('Helvetica', size, textColor, true); tf.autoSize = TextFieldAutoSize.LEFT; tf.text = buttonLabel; bd = new BitmapData(tf.width+TAIL_LENGTH, tf.height, true, bgColor+(0xff<<24)); bd.lock(); bd.fillRect(new Rectangle(tf.width,0,TAIL_LENGTH,tf.height),0x0); bd.draw(tf); var prev:Particle = particles = new Particle(); var p:Particle; for (var i:int=0; i < tf.width; i++) { for (var j:int=0; j < tf.height; j++) { var color:uint = bd.getPixel(i, j); if ( color != bgColor ) { p = new Particle(); p.x = i; p.y = j; p.sx = (Math.random()+1)*(i+1)*200 + DISTANCE; p.sy = p.y; p.cx = p.sx; p.cy = p.sy; p.vx = 2 + Math.random()*i/200; p.vy = 2; p.color = color; prev.next = p; prev = p; pnum++; } else { bd.setPixel32(i, j, 0x0); } } } bd.unlock(); if( _setup ) { addChild( new Bitmap( bd ) ); initEvent(); } } private function initEvent():void { var over:Sprite = new Sprite(); over.graphics.beginFill(0x0, 0); over.graphics.drawRect(0,0,bd.width,bd.height); over.graphics.endFill(); addChild( over ); over.addEventListener( MouseEvent.MOUSE_OVER, clickHandler ); } public function appearMotion():void { if( !_setup ) { bd.fillRect(bd.rect,0x0); addChild( new Bitmap( bd ) ); initEvent(); } motion(); } private function clickHandler(e:Event):void { motion(); } private function motion():void { var p:Particle = particles; while((p = p.next) != null) { p.cx = p.sx; p.cy = p.sy; } if( !hasEventListener( Event.ENTER_FRAME ) ) { addEventListener( Event.ENTER_FRAME, update ); } } private function update(e:Event):void { var num:int = 0; var p:Particle = particles; bd.lock(); bd.fillRect(bd.rect, 0x0); while((p = p.next) != null) { var r:Number = Math.sqrt((p.x-p.cx)*(p.x-p.cx) + (p.y-p.cy)*(p.y-p.cy)); p.cx += (p.x - p.cx )/p.vx; p.cy += (p.y - p.cy )/p.vy; if ( Math.abs( p.cx - p.x ) <= 1 && Math.abs( p.cy - p.y) <= 1) { p.cx = p.x; p.cy = p.y; num++; } var a:uint = r < APPEAR_RANGE ? (1-r/APPEAR_RANGE)*255 : 0; var c:uint = p.color + (a << 24); bd.setPixel32(p.cx, p.cy, c); } bd.unlock(); if(pnum == num) { e.target.removeEventListener(Event.ENTER_FRAME,arguments.callee); } } } class Particle { public var color:int; public var x:Number; public var y:Number; public var cx:Number; public var cy:Number; public var sx:Number; public var sy:Number; public var vx:Number; public var vy:Number; public var next:Particle; public function Particle() { } } Sand Button