// forked from bouze's hybrid-brush-06 // forked from bouze's hybrid-brush-05 // forked from bouze's hybrid-brush-04 // forked from bouze's hybrid-brush-03 // forked from bouze's hybrid-brush-02 // forked from bouze's hybrid-brush-01 package { import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.BlendMode; import flash.display.GradientType; import flash.display.Graphics; import flash.display.Sprite; import flash.display.StageAlign; import flash.display.StageQuality; import flash.display.StageScaleMode; import flash.events.Event; import flash.filters.BlurFilter; import flash.geom.ColorTransform; import flash.geom.Matrix; import flash.geom.Point; /** * ... * @author bouze */ [SWF(frameRate="60", backgroundColor="#BBCC99")] public class Main extends Sprite { private var drawLayer:Sprite; private var particles:Array = new Array(); private var pNum:int = 10; private var maxDistance:Number = 30; private var friction:Number = 0.90; private var gravity:Number = 0.01; private var hardness:Number = 0.2; private var joinPointNum:int = 5; private var canvas:BitmapData; private var refreshRate:int = 1; private var blurRate:int = 5; private var counter:int = 0; public function Main() { init(); } private function init():void { stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; stage.quality = StageQuality.LOW; drawLayer = new Sprite(); addChild( drawLayer ); initCanvas(); initParticles(); addEventListener( Event.ENTER_FRAME, update ); stage.addEventListener( Event.RESIZE, setupCanvas ); } private function update(e:Event):void { move(); draw(); capture(); } private function initParticles():void { var i:int; for (i = 0; i < pNum; i++) { var sp:Sprite = new Sprite(); //sp.blendMode = BlendMode.OVERLAY; drawLayer.addChild( sp ); particles[ i ] = { x: mouseX, y: mouseY, ref: sp, vx: 0, vy: 0 }; } } private function initCanvas():void { if ( canvas ) { canvas.dispose(); } canvas = new BitmapData( stage.stageWidth - 1, stage.stageHeight, true, 0x000000 ); var bm:Bitmap = new Bitmap( canvas ); addChild( bm ); } private function setupCanvas(e:Event):void { initCanvas(); } private function capture():void { if ( counter % refreshRate == 0 ) { canvas.lock(); canvas.draw( drawLayer ); var ct:ColorTransform = new ColorTransform(); if ( counter % blurRate == 0 ) { //canvas.applyFilter( canvas, canvas.rect, new Point(), new BlurFilter( 1.1, 1.1, 1 ) ); ct = new ColorTransform( 1.0, 0.99, 1.0, 0.99, 0, 0, 0, 0 ); } canvas.colorTransform( canvas.rect, ct ); canvas.unlock(); } counter++; } private function move():void { particles[ 0 ].x = stage.mouseX; particles[ 0 ].y = stage.mouseY; var c:Number; for ( c = 1; c < pNum; c++) { var p:Object = particles[ c ]; var pp:Object = particles[ c - 1 ]; p.vx *= friction; p.vy *= friction; //尻の方が重たくなるように p.vy += gravity * c * 0.3; p.x += p.vx; p.y += p.vy; var X:Number = p.x - pp.x; var Y:Number = p.y - pp.y; var distance:Number = Math.sqrt( X * X + Y * Y ); var angle:Number = Math.atan2( Y, X ); if ( distance > maxDistance ) { var ox:Number = p.x; var oy:Number = p.y; //強く引っ張ったら伸びるように var tx:Number = pp.x + maxDistance * Math.cos( angle ); var ty:Number = pp.y + maxDistance * Math.sin( angle ); p.x += ( tx - p.x ) * hardness; p.y += ( ty - p.y ) * hardness; //p.x = pp.x + maxDistance * Math.cos( angle ); //p.y = pp.y + maxDistance * Math.sin( angle ); p.vx += ( p.x - ox ) * 0.1; p.vy += ( p.y - oy ) * 0.1; } } } private function draw():void { var i:int; for (i = 0; i < pNum - joinPointNum; i++) { var p:Array = particles; var mtrx:Matrix = new Matrix(); mtrx = createLinearGradientMatrix( p[ i ].x, p[ i ].y, p[ i + joinPointNum ].x, p[ i + joinPointNum ].y) var g:Graphics = p[ i ].ref.graphics; g.clear(); g.beginGradientFill(GradientType.LINEAR, [ 0xFF00AA, 0x00DDDD ], [ 0.3, 0.1 ], [ 96, 255 ], mtrx); //g.moveTo( p[ i ].x, p[ i ].y ); //curveThrough3Pts(g, p[ i ].x, p[ i ].y, p[ i + 1 ].x, p[ i + 1 ].y, p[ i + 2 ].x, p[ i + 2 ].y ); //curveThrough3Pts(g, p[ i + 2 ].x, p[ i + 2 ].y, p[ i + 3 ].x, p[ i + 3 ].y, p[ i + 4 ].x, p[ i + 4 ].y ); g.moveTo( p[ i ].x, p[ i ].y ); var n:int for ( n = 1; n <= joinPointNum; n++ ) { g.lineTo( p[ i + n ].x, p[ i + n ].y ); } g.lineTo( p[ i ].x, p[ i ].y ); g.endFill(); } } /** * 三点を通る二次元曲線 * via 詳説ActionScript 3.0(p.700) */ /* private function curveThrough3Pts ( g:Graphics, startX:Number, startY:Number, throughX:Number, throughY:Number, endX:Number, endY:Number ):void { var controlX:Number = ( 2 * throughX ) - 0.5 * ( startX + endX ); var controlY:Number = ( 2 * throughY ) - 0.5 * ( startY + endY ); g.moveTo( startX, startY ); g.curveTo( controlX, controlY, endX, endY ); } */ /** * Make matrix for linear gradient * via http://nutsu.com/blog/2009/020921_as_gradient_matrix.html */ private function createLinearGradientMatrix( x0:Number, y0:Number, x1:Number, y1:Number ):Matrix { var mtrx:Matrix = new Matrix(); mtrx.createGradientBox( 1, 1, 0, -0.5, -0.5 ); var vx:Number = x1 - x0; var vy:Number = y1 - y0; var w:Number = Math.sqrt( vx * vx + vy * vy ); var r:Number = Math.atan2( vy, vx ); var cx:Number = ( x0 + x1 ) / 2; var cy:Number = ( y0 + y1 ) / 2; mtrx.scale( w, 1 ); mtrx.rotate( r ); mtrx.translate( cx, cy ); return mtrx; } } } hybrid-brush-07