forked from: forked from: Hair ff: IK Long Fiber
IKで糸の束っぽいもの( 少し重いです。 )
ramirobazan: I've just improved a little bit the performance
/**
* Copyright ramiro.bazan ( http://wonderfl.net/user/ramiro.bazan )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/1owz
*/
// forked from shengbanx's forked from: Hair ff: IK Long Fiber
// forked from alexnotkin's Hair ff: IK Long Fiber
// forked from clockmaker's IK Long Fiber
// forked from whirlpower's IK Fiber
/**
IKで糸の束っぽいもの( 少し重いです。 )
ramirobazan: I've just improved a little bit the performance
*/
package {
import flash.display.Sprite;
[SWF(frameRate=60)]
public class FlashTest extends Sprite {
public function FlashTest() {
// write as3 code here..
stage.quality = "medium";
stage.addChild( new TailLine() );
}
}
}
import flash.utils.Dictionary;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
internal class TailLine extends Bitmap
{
private var lines :Vector.<IKline>;
static private const MAX_HAIRS : int = 250;
public function TailLine():void
{
addEventListener( Event.ADDED_TO_STAGE, init );
}
static private const PI_2 : Number = Math.PI * 2;
private function init( e:Event ):void
{
removeEventListener( Event.ADDED_TO_STAGE, init );
bitmapData = new BitmapData( stage.stageWidth, stage.stageHeight, true, 0x00000000 );
lines = new Vector.<IKline>(MAX_HAIRS);
for (var i:int = 0; i < MAX_HAIRS; i++)
{
var radius :Number = Math.random() * 0;
var radian :Number = Math.random() * PI_2;
var line:IKline = new IKline();
line.x = Math.cos( radian ) * radius;
line.y = Math.sin( radian ) * radius;
line.segmentLeng = 20;
line.segmentNum = 8;
line.gravity = 0;
line.friction = Math.random() * 0.1 + 0.85;
line.color = 0x000000;
lines[i] = line;
}
lines.fixed = true;
addEventListener( Event.ENTER_FRAME, loop );
}
static private var matrix : Matrix = new Matrix();
private function loop( evt:Event ):void
{
var _x :Number = stage.mouseX;
var _y :Number = stage.mouseY;
bitmapData.lock();
bitmapData.fillRect( bitmapData.rect, 0x00 );
for(var i : int = 0;i<MAX_HAIRS;i++)
{
var line : IKline = lines[i];
line.nextFrame( _x, _y );
matrix.identity();
matrix.translate(line.x,line.y);
bitmapData.draw( drawLine( line ), matrix);
}
bitmapData.unlock();
}
private var shape : Shape = new Shape();
private function drawLine( line:IKline ):Shape
{
var segments:Vector.<Segment> = line.segments;
var leng :int = segments.length;
var g :Graphics = shape.graphics;
g.clear();
g.moveTo( segments[0].x, segments[0].y );
for ( var i :int = 0; i < leng-2; i++ )
{
var xc:Number = ( segments[i].x + segments[i + 1].x ) * 0.5;
var yc:Number = ( segments[i].y + segments[i + 1].y ) * 0.5;
g.lineStyle( 1-i/(leng-2), line.color, 1-i/(leng-2) );
g.curveTo( segments[i].x, segments[i].y, xc, yc );
}
return shape;
}
}
internal class IKline
{
public var segments :Vector.<Segment>;
public var x :Number = 0;
public var y :Number = 0;
public var segmentLeng :int = 60;
public var segmentNum :int = 8;
public var gravity :Number = 1;
public var friction :Number = 1;
public var color :uint = 0x000000;
public function IKline():void
{
this.gravity = gravity;
this.friction = friction;
segments = new Vector.<Segment>(segmentNum);
var segment:Segment = new Segment( 0 * i );
segments[0] = segment;;
for (var i:int = 1; i < segmentNum; i++)
{
segment = new Segment( segmentLeng-0.5 * i );
segments[i] = segment;
}
segments.fixed = true;
}
private var _oldX:Number = 0;
private var _oldY:Number = 0;
public function nextFrame( _x:int, _y:int ):void
{
_oldX += (_x - _oldX) * 0.1;
_oldY += (_y - _oldY) * 0.1;
drag( segments[0], _oldX, _oldY );
for ( var i:int = 1; i < segmentNum; i++ )
{
var segmentA:Segment = segments[i];
var segmentB:Segment = segments[i - 1];
drag( segmentA, segmentB.x, segmentB.y );
}
}
static private const TO_DEGRESS : Number = 180 / Math.PI;
private function drag( segment:Segment, xpos:Number, ypos:Number ):void
{
segment.next();
var dx :Number = xpos - segment.x;
var dy :Number = ypos - segment.y;
var radian :Number = Math.atan2( dy, dx );
segment.rotation = radian * TO_DEGRESS;
var pin :Point = segment.getPin();
var w :Number = pin.x - segment.x;
var h :Number = pin.y - segment.y;
segment.x = xpos - w;
segment.y = ypos - h;
segment.setVector();
segment.vx *= friction;
segment.vy *= friction;
segment.vy += gravity;
}
}
internal class Segment extends Sprite
{
static private const TO_RADIANS : Number = Math.PI / 180;
private var segmentLeng :Number;
public var vx :Number = 0;
public var vy :Number = 0;
private var prevX :Number = 0;
private var prevY :Number = 0;
public function Segment( segmentLeng:Number ):void
{
this.segmentLeng = segmentLeng;
}
public function next():void
{
x += vx;
y += vy;
}
public function setVector():void
{
if( prevX ) vx = x - prevX;
if( prevY ) vy = y - prevY;
prevX = x;
prevY = y;
}
static private var tempPoint : Point = new Point();
public function getPin():Point
{
var angle :Number = rotation * TO_RADIANS;
var sin : Number = Math.sin(angle);
var cos : Number = Math.cos(angle);
var xpos :Number = x + cos * segmentLeng;
var ypos :Number = y + sin * segmentLeng;
tempPoint.x = xpos;
tempPoint.y = ypos;
return tempPoint;
}
}