// Elastic String(残像版) // Elastic Pixels(残像版) の発展 // // forked from Aquioux's forked from: Elastic Pixels(残像版) // Elastic Pixels 2 残像版 // forked from Aquioux's Elastic Pixels // Elastic Pixels 1 // あちこちのコードをパッチワーク package { /** * @author YOSHIDA, Akio */ import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Matrix; import flash.geom.Point; import flash.geom.ColorTransform; [SWF(width = "465", height = "465", frameRate = "60", backgroundColor = "#000000")] public class Main2 extends Sprite { private var aryParticle:Array; // パーティクル格納配列 private var isMouseDown:Boolean = false; // マウスをダウンしているか否か private var distanceOfReaction:uint = 100; // マウスに反応する距離 private var spring:Number = 0.075; // バネ係数 private var friction:Number = 0.93; // 摩擦係数 private var bmdCaptured:BitmapData; // Particle を打つ BitmapData private var bmdDisplay:BitmapData; // 表示する BitmapData private var tpx:TextPixelizer; private const TONEDOWN:ColorTransform = new ColorTransform(1, 0.9, 0.25, 0.7); // コンストラクタ public function Main2() { var w:uint = stage.stageWidth; var h:uint = stage.stageHeight; bmdCaptured = new BitmapData(w, h, true, 0xff000000); bmdDisplay = new BitmapData(w, h, true, 0xff000000); addChild(new Bitmap(bmdDisplay)); tpx = new TextPixelizer("_serif", 60, 0x000000); tpx.addEventListener(PixelizerEvent.COMPLETE, completeHandler); tpx.pixelize("wonderfl\nbuild flash\nonline"); } private function completeHandler(e:PixelizerEvent):void { var offsetX:Number = (stage.stageWidth - tpx.width) / 2; var offsetY:Number = (stage.stageHeight - tpx.height) / 2; var data:Vector.<Pixel> = tpx.data; aryParticle = []; for each(var pixel:Pixel in data) { var alpha:uint = tpx.getAlpha(pixel.color); if (alpha > 0x7f) { var particle:Particle = new Particle(pixel.x + offsetX, pixel.y + offsetY); aryParticle.push(particle); } } tpx = null; stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler); stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler); addEventListener(Event.ENTER_FRAME, enterFrameHandler); } private function enterFrameHandler(e:Event):void { bmdCaptured.lock(); bmdCaptured.fillRect(bmdCaptured.rect, 0x00000000); var mousePoint:Point = new Point(mouseX, mouseY); for each (var particle:Particle in aryParticle) { particle.update(mousePoint, isMouseDown, distanceOfReaction, spring, friction); bmdCaptured.setPixel32(particle.x, particle.y, 0xffffffff); } bmdCaptured.unlock(); bmdDisplay.colorTransform(bmdDisplay.rect, TONEDOWN); bmdDisplay.draw(bmdCaptured); } private function mouseDownHandler(e:MouseEvent):void { isMouseDown = true; } private function mouseUpHandler(e:MouseEvent):void { isMouseDown = false; } } } import flash.geom.Point; class Particle { // 既定座標 private var localX:Number; private var localY:Number; // ベロシティ private var vx:Number = 0; private var vy:Number = 0; // 現在座標 private var _x:Number; private var _y:Number; private var offset:int; public function Particle(x:Number, y:Number) { _x = localX = x; _y = localY = y; offset = Math.floor(Math.random()) * 30 - 15; } public function update(mousePoint:Point, isMouseDown:Boolean, distanceOfReaction:uint, spring:Number, friction:Number):void { // 到達値 var dx:Number; var dy:Number; var distance:Number = Point.distance(mousePoint, new Point(localX, localY)); var direction:Number = isMouseDown ? 1 : -1; if (distance < distanceOfReaction) { var diff:Number = distance * direction * (distanceOfReaction - distance) / distanceOfReaction + offset; var radian:Number = Math.atan2(mousePoint.y - localY, mousePoint.x - localX); var diffPoint:Point = Point.polar(diff, radian); dx = localX + diffPoint.x; dy = localY + diffPoint.y; } else{ // 位置を元に戻す dx = localX; dy = localY; } vx += (dx - _x) * spring; vy += (dy - _y) * spring; vx *= friction; vy *= friction; _x += vx; _y += vy; } public function get x():Number { return _x; } public function get y():Number { return _y; } } class Pixel { private var _x:Number; private var _y:Number; private var _color:uint; // 32 bit color public function Pixel(x:Number, y:Number, color:uint) { _x = x; _y = y; _color = color; } public function get x():Number { return _x; } public function get y():Number { return _y; } public function get color():uint { return _color; } public function set x(value:Number):void { _x = value; } public function set y(value:Number):void { _y = value; } public function set color(value:uint):void { _color = value; } } import flash.display.BitmapData; import flash.events.Event; import flash.events.EventDispatcher; class Pixelizer extends EventDispatcher { // ピクセル格納ベクター private var _data:Vector.<Pixel>; // スキャンサイズ private var _width:uint = 0; // 幅 private var _height:uint = 0; // 高 public function Pixelizer() {} // 走査 public function scan(bmd:BitmapData):void { var w:uint = _width = bmd.width; var h:uint = _height = bmd.height; var i:uint = 0; _data = new Vector.<Pixel>(w*h, true); for (var y:uint = 0; y < h; y++){ for (var x:uint = 0; x < w; x++){ _data[i++] = new Pixel(x, y, bmd.getPixel32(x, y)); } } // BitmapData 消去 bmd.dispose(); // イベント発行 dispatchEvent(new PixelizerEvent(PixelizerEvent.COMPLETE)); } // 32 bit color のアルファ値を取得 public function getAlpha(c:uint):uint { return (c >> 24) & 0xff; } // getter(pixelize 実行後に有効) public function get data():Vector.<Pixel> { return _data; } public function get width():uint { return _width; } public function get height():uint { return _height; } } import flash.display.BitmapData; import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Matrix; import flash.text.TextField; import flash.text.TextFormat; class TextPixelizer extends EventDispatcher { // バックエンドクラス private var px:Pixelizer; // テキストフォーマット用変数 private var _font:String = "_serif";// フォント名 private var _size:uint = 16; // フォントサイズ private var _color:uint = 0x000000; // フォントカラー static public const TRANSPARENT:uint = 0x00000000; public function TextPixelizer(font:String = "_serif", size:uint = 16, color:uint = 0x000000) { _font = font; _size = size; _color = color; } // ピクセル情報作成 public function pixelize(str:String):void { // バックエンドクラス設定 px = new Pixelizer(); px.addEventListener(PixelizerEvent.COMPLETE, completeHandler); // TextField 生成 var fld:TextField = new TextField(); fld.defaultTextFormat = new TextFormat(_font, _size, _color); fld.text = str; fld.autoSize = "left"; // BitmapData 生成 var w:Number = fld.width - 4; var h:Number = fld.height - 4; var bmd:BitmapData = new BitmapData(w, h, true, TRANSPARENT); bmd.draw(fld, new Matrix(1, 0, 0, 1, -2, -2)); // 走査 px.scan(bmd); } private function completeHandler(e:Event):void { dispatchEvent(new PixelizerEvent(PixelizerEvent.COMPLETE)); } // 32 bit color のアルファ値を取得 public function getAlpha(c:uint):uint { return px.getAlpha(c); } // getter(pixelize 実行後に有効) public function get data():Vector.<Pixel> { return px.data; } public function get width():uint { return px.width; } public function get height():uint { return px.height; } // setter(pixelize 実行前のみ有効) public function set font(value:String):void { _font = value; } public function set size(value:uint):void { _size = value; } public function set color(value:uint):void { _color = value; } } import flash.events.Event; class PixelizerEvent extends Event { public static const COMPLETE:String = "complete"; public function PixelizerEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false) { super(type, bubbles, cancelable); } public override function clone():Event { return new PixelizerEvent(type, bubbles, cancelable); } public override function toString():String { return formatToString("PixelizerEvent", "type", "bubbles", "cancelable", "eventPhase"); } } Elastic String (残像版)