flash on 2013-11-26
/**
* Copyright shaktool ( http://wonderfl.net/user/shaktool )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/t5MT
*/
package
{
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.geom.*;
import flash.text.*;
import flash.utils.*;
import flash.ui.*;
[SWF(width=465, height=465, frameRate=30, backgroundColor=0x000000)]
public class FlashTest extends Sprite
{
private var foreground: Graphics;
private var turbulence: BitmapData = new BitmapData( NOISE_LENGTH, NOISE_LENGTH, false, 0 );
private var roots: Array = [];
private var time: Number = 0.0;
private var prevMousePos: Vector.<Number> = new <Number>[ 200, 200 ];
private var vacuumPos: Vector.<Number> = new <Number>[ 200, 200 ];
private var vacuumSpeed: Number = 0.0;
public function FlashTest()
{
var i: int, j: int, k: int;
var sprite: Sprite;
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
// Background gradient:
sprite = new Sprite();
addChild( sprite );
var background: Graphics = sprite.graphics;
var matrix: Matrix = new Matrix();
matrix.createGradientBox( WIDTH, HEIGHT * 0.25, -Math.PI * 0.5, 0, HEIGHT * 0.75 );
background.beginGradientFill( GradientType.LINEAR, [ 0xffffff, 0x0077ff ], null, [ 0, 255 ], matrix );
background.drawRect( 0, 0, WIDTH, HEIGHT );
background.endFill();
sprite = new Sprite();
addChild( sprite );
foreground = sprite.graphics;
turbulence.perlinNoise( 32, 32, 5, Math.random()*int.MAX_VALUE, true, true, 3, false );
//addChild( new Bitmap( turbulence ) );
for ( j = 0; j < TENDRIL_COUNT; j++ )
{
var prevNode: Node = null;
for ( i = 0; i < 10; i++ )
{
var node: Node = new Node( new <Number>[ ( j + 0.5 ) * WIDTH / TENDRIL_COUNT, HEIGHT - i * JOINT_LENGTH * 0.5 ], i, null );
if ( prevNode != null )
{
prevNode.next = node;
}
else
{
roots.push( node );
node.isRoot = true;
}
prevNode = node;
}
}
}
private function onEnterFrame( event: Event = null ): void
{
var i: int, j: int, k: int;
var root: Node, nextNode: Node, prevNode: Node;
var dt: Number = 0.033333333;
time += dt;
// Shove nodes around:
var mousePos: Vector.<Number> = new <Number>[ mouseX, mouseY ];
var dragSpeed: Number = Math.min( 1.0, vecLength( subtract( mousePos, prevMousePos ) ) / MAX_SPEED );
for ( i = 0; i < roots.length; i++ )
{
root = roots[ i ];
for ( nextNode = root; nextNode != null; nextNode = nextNode.next )
{
if ( nextNode.isRoot ) continue;
nextNode.age += dt;
nextNode.pos = add( nextNode.pos, windAt( nextNode.pos, root.pos[ 0 ] ) );
nextNode.pos[ 1 ] -= WIND_RISE;
var mouseOffset: Vector.<Number>;
var mouseDistance: Number;
var mouseOffsetScale: Number;
mouseOffset = subtract( nextNode.pos, mousePos );
mouseDistance = Math.max( 5.0, vecLength( mouseOffset ) );
mouseOffsetScale = Math.max( 0.0, ( DRAG_RANGE - mouseDistance ) / mouseDistance );
nextNode.pos = add( nextNode.pos, multiply( mouseOffset, dragSpeed * mouseOffsetScale * DRAG_FORCE ) );
mouseOffset = subtract( vacuumPos, nextNode.pos );
mouseDistance = Math.max( 5.0, vecLength( mouseOffset ) );
mouseOffsetScale = Math.max( 0.0, ( VACUUM_RANGE - mouseDistance ) / mouseDistance );
nextNode.pos = add( nextNode.pos, multiply( mouseOffset, vacuumSpeed * mouseOffsetScale * VACUUM_FORCE ) );
}
}
var vacuumLerp: Number = VACUUM_SNAPPINESS * dt;
vacuumPos = add( multiply( mousePos, vacuumLerp ), multiply( vacuumPos, 1.0 - vacuumLerp ) );
vacuumSpeed = dragSpeed * vacuumLerp + vacuumSpeed * ( 1.0 - vacuumLerp );
prevMousePos = mousePos;
// Maintain or break chains
for ( i = 0; i < roots.length; i++ )
{
root = roots[ i ];
prevNode = root;
for ( nextNode = root.next; nextNode != null; nextNode = nextNode.next )
{
var offset: Vector.<Number> = subtract( nextNode.pos, prevNode.pos );
if ( prevNode != root || !root.isRoot )
{
if ( nextNode.age > JOINT_LIFETIME )
{
prevNode.next = null;
if ( prevNode == root ) roots.splice( roots.indexOf( prevNode ), 1 );
}
else if ( Math.random() < 0.005 )
{
var splitNode: Node = new Node( new <Number>[ prevNode.pos[ 0 ], prevNode.pos[ 1 ] ], prevNode.age, nextNode )
prevNode.next = null;
if ( prevNode == root ) roots.splice( roots.indexOf( prevNode ), 1 );
roots.push( splitNode );
}
else
{
var offsetScale: Number = Math.min( 50.0, Math.max( -50.0, vecLength( offset ) - JOINT_LENGTH * ( 1.0 - nextNode.age / JOINT_LIFETIME ) ) );
prevNode.pos = add( prevNode.pos, multiply( offset, offsetScale * 0.01 ) );
nextNode.pos = add( nextNode.pos, multiply( offset, -offsetScale * 0.01 ) );
}
}
else if ( vecLength( offset ) > JOINT_LENGTH )
{
var newNode: Node = new Node( new <Number>[ root.pos[ 0 ], root.pos[ 1 ] ], 0.0, nextNode );
root.next = newNode;
}
prevNode = nextNode;
}
}
// Display all nodes:
foreground.clear();
for ( i = 0; i < roots.length; i++ )
{
root = roots[ i ];
foreground.moveTo( root.pos[ 0 ], root.pos[ 1 ] );
prevNode = root;
nextNode = root.next;
for ( nextNode = root.next; nextNode != null; nextNode = nextNode.next )
{
foreground.lineStyle( TENDRIL_THICKNESS * ( 1.0 - nextNode.age / JOINT_LIFETIME ), 0xffffff, 0.5 );
foreground.lineTo( nextNode.pos[ 0 ], nextNode.pos[ 1 ] );
prevNode = nextNode;
}
}
}
private function windAt( point: Vector.<Number>, offset: Number ): Vector.<Number>
{
var sampleX: Number = ( point[ 0 ] * 0.2 + time * 1.0 + offset * 0.6 ) % NOISE_LENGTH;
var sampleY: Number = ( point[ 1 ] * 0.2 + time * 15.0 ) % NOISE_LENGTH;
if ( sampleX < 0.0 ) sampleX += NOISE_LENGTH;
if ( sampleY < 0.0 ) sampleY += NOISE_LENGTH;
var color: uint = turbulence.getPixel32( sampleX, sampleY );
var windX: Number = ( ( color & 0xff0000 ) >> 16 ) / 127.5 - 1.0;
var windY: Number = ( ( color & 0xff00 ) >> 8 ) / 127.5 - 1.0;
return new <Number>[ windX * WIND_SPEED, windY * WIND_SPEED ];
}
}
}
const WIDTH: int = 465;
const HEIGHT: int = 465;
const NOISE_LENGTH: int = 256;
const TENDRIL_COUNT: int = 30.0;
const TENDRIL_THICKNESS: Number = 50.0;
const JOINT_LENGTH: Number = 40.0;
const JOINT_LIFETIME: Number = 15.0;
const WIND_SPEED: Number = 4.0;
const WIND_RISE: Number = 0.5;
const MAX_SPEED: Number = 12.0;
const DRAG_RANGE: Number = 100.0;
const DRAG_FORCE: Number = 0.3;
const VACUUM_RANGE: Number = 125.0;
const VACUUM_FORCE: Number = 0.1;
const VACUUM_SNAPPINESS: Number = 6.0;
class Node
{
public var pos: Vector.<Number>;
public var age: Number;
public var next: Node;
public var isRoot: Boolean = false;
public function Node( pos: Vector.<Number>, age: Number, next: Node )
{
this.pos = pos;
this.age = age;
this.next = next;
}
}
function add( a: Vector.<Number>, b: Vector.<Number> ): Vector.<Number> { return new <Number>[ a[ 0 ] + b[ 0 ], a[ 1 ] + b[ 1 ] ]; }
function subtract( a: Vector.<Number>, b: Vector.<Number> ): Vector.<Number> { return new <Number>[ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ] ]; }
function multiply( a: Vector.<Number>, b: Number ): Vector.<Number> { return new <Number>[ a[ 0 ] * b, a[ 1 ] * b ]; }
function vecLength( a: Vector.<Number> ): Number { return Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] ); }
function dot( a: Vector.<Number>, b: Vector.<Number> ): Number { return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ]; }
function SafeNormalize( a: Vector.<Number> ): Vector.<Number> { var len: Number = vecLength( a ); return len == 0.0 ? new <Number>[ 0.0, 0.0 ] : new <Number>[ a[ 0 ] / len, a[ 1 ] / len ]; }