IKhandle and Doll
Drag a red circles
/**
* Copyright whirlpower ( http://wonderfl.net/user/whirlpower )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wpb4
*/
/*
Drag a red circles
*/
package
{
import flash.display.*;
import flash.events.Event;
[SWF(width = 465, height = 465, frameRate = 30)]
public class Main extends Sprite
{
private var doll : Doll;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
doll = new Doll();
addChild( doll );
}
}
}
import flash.display.*;
import flash.events.*;
import flash.geom.Point;
internal class NodeObject extends Sprite
{
private var _ikParent:DollParts;
public function get ikParent():DollParts { return _ikParent; }
public function set ikParent(v:DollParts):void { _ikParent = v; }
private var _ikX:Number;
public function get ikX():Number
{
positioning();
return _ikX;
}
private var _ikY:Number;
public function get ikY():Number
{
positioning();
return _ikY;
}
public function NodeObject( _x:int, _y:int ):void
{
this.x = _x;
this.y = _y;
}
private function positioning():void
{
var p : Point = parent.localToGlobal( new Point( x,y ) );
_ikX = _ikParent.globalToLocal( p ).x;
_ikY = _ikParent.globalToLocal( p ).y;
}
}
internal class IkTarget extends NodeObject
{
public function IkTarget( _x:int, _y:int ):void
{
super( _x, _y );
graphics.beginFill( 0xFF0000, 0.2 );
graphics.drawCircle( 0, 0, 15 );
graphics.endFill();
addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
}
private function mouseDownHandler(e:MouseEvent):void
{
removeEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
startDrag();
addEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
}
private function mouseUpHandler(e:MouseEvent):void
{
removeEventListener( MouseEvent.MOUSE_UP, mouseUpHandler );
stopDrag();
addEventListener( MouseEvent.MOUSE_DOWN, mouseDownHandler );
}
}
internal class Doll extends NodeObject
{
private var _rootTarget : IkTarget; // ルート移動用
private var _headTarget : IkTarget; // 頭のIK目標点
private var _bodyTarget : IkTarget; // 体のIK目標点
private var _leftArmTarget : IkTarget; // 左手のIK目標点
private var _rightArmTarget : IkTarget; // 右手のIK目標点
private var _leftLegTarget : IkTarget; // 左足のIK目標点
private var _rightLegTarget : IkTarget; // 右足のIK目標点
private var _head : DollParts; // 頭
private var _body : DollParts; // 体
private var _leftArm : DollParts; // 左手
private var _rightArm : DollParts; // 右手
private var _leftLeg : DollParts; // 左足
private var _rightLeg : DollParts; // 右足
public function Doll():void
{
super( 230, 300 );
init();
}
public function init():void
{
var param/*SegmentParam*/:Array;
// 体
param = new Array();
param.push( new SegmentParam( 20, 20 ) );
param.push( new SegmentParam( 20, 20 ) );
param.push( new SegmentParam( 20, 20 ) );
param.push( new SegmentParam( 20, 20 ) );
_body = setDollParts( this, param, 0, 0 );
_bodyTarget = setTarget( _body, _body, 0, -80 );
// 頭
param = new Array();
param.push( new SegmentParam( 50, 20 ) );
_head = setDollParts( _body.getSegmentAt(0), param, 50, 0 );
_headTarget = setTarget( _body.getSegmentAt(0), _head, 100, 0 );
// 左手
param = new Array();
param.push( new SegmentParam( 50, 20 ) );
param.push( new SegmentParam( 50, 20 ) );
_leftArm = setDollParts( _body.getSegmentAt(0), param, 40, -40 );
_leftArmTarget = setTarget( _body.getSegmentAt(0), _leftArm, -50, -100 );
// 右手
param = new Array();
param.push( new SegmentParam( 50, 20 ) );
param.push( new SegmentParam( 50, 20 ) );
_rightArm = setDollParts( _body.getSegmentAt(0), param, 40, 40 );
_rightArmTarget = setTarget( _body.getSegmentAt(0), _rightArm, -50, 100 );
// 左足
param = new Array();
param.push( new SegmentParam( 60, 20 ) );
param.push( new SegmentParam( 70, 20 ) );
_leftLeg = setDollParts( _body, param, -30, 0 );
_leftLegTarget = setTarget( this, _leftLeg, -30, 130 );
// 右足
param = new Array();
param.push( new SegmentParam( 60, 20 ) );
param.push( new SegmentParam( 70, 20 ) );
_rightLeg = setDollParts( _body, param, 30, 0 );
_rightLegTarget = setTarget( this, _rightLeg, 30, 130 );
_rootTarget = new IkTarget( 0, 0 );
addChild( _rootTarget );
addEventListener( Event.ENTER_FRAME, loop );
}
private function setDollParts( _parent:DisplayObjectContainer, _param:Array, _x:int, _y:int ):DollParts
{
var parts : DollParts = new DollParts( _param );
parts.x = _x;
parts.y = _y;
_parent.addChild( parts );
return parts;
}
private function setTarget( _parent:DisplayObjectContainer, _ikParent:DollParts, _x:int, _y:int ):IkTarget
{
var target:IkTarget = new IkTarget( _x, _y );
target.ikParent = _ikParent;
_parent.addChild( target );
return target
}
private function loop( event:Event ):void
{
_body.x = _rootTarget.x;
_body.y = _rootTarget.y;
_body.upDate( _bodyTarget.ikX, _bodyTarget.ikY );
_head.upDate( _headTarget.ikX, _headTarget.ikY );
_leftArm.upDate( _leftArmTarget.ikX, _leftArmTarget.ikY );
_rightArm.upDate( _rightArmTarget.ikX, _rightArmTarget.ikY );
_leftLeg.upDate( _leftLegTarget.ikX, _leftLegTarget.ikY );
_rightLeg.upDate( _rightLegTarget.ikX, _rightLegTarget.ikY );
}
}
internal class DollParts extends Sprite
{
private var segments /*Segment*/:Array;
public function getSegmentAt( num:int ):Segment
{
return segments[ num ];
}
public function DollParts( params/*SegmentParam*/:Array ):void
{
segments = new Array();
for each( var seg:SegmentParam in params )
{
var segment : Segment = new Segment( seg );
addChild( segment );
segments.push( segment );
}
}
public function upDate( targetX:int, targetY:int ):void
{
var target : Point = new Point( targetX, targetY );
var leng : int = segments.length;
for ( var i : int = 0; i < leng; i++ )
{
target = reach( segments[i], target.x, target.y );
if ( i >= 1 )
{
var pin : Point = segments[i].getPin();
segments[i-1].x = pin.x;
segments[i-1].y = pin.y;
}
}
}
private function reach( segment:Segment, px:Number, py:Number ):Point
{
var dx:Number = px - segment.x;
var dy:Number = py - segment.y;
var angle:Number = Math.atan2(dy, dx);
segment.rotation = angle * 180 / Math.PI;
var pin : Point = segment.getPin();
var w : Number = pin.x - segment.x;
var h : Number = pin.y - segment.y;
var tx : Number = px - w;
var ty : Number = py - h;
return new Point(tx, ty);
}
}
internal class Segment extends Sprite
{
private var _length : int;
private var _width : int;
private static var colors:Array = [ 0xff0000, 0x00ff00, 0x0000ff ];
private static var count:int = 0;
public function Segment( segmentParam:SegmentParam )
{
this._length = segmentParam.length;
this._width = segmentParam.width;
graphics.beginFill( colors[count%3], 0.2 );
graphics.drawRect( -_width / 2, -_width / 2, _width + _length, _width );
count++;
graphics.drawCircle(0, 0, 4 );
graphics.drawCircle( _length, 0, 2);
graphics.endFill();
mouseEnabled = false;
}
public function getPin():Point
{
var angle:Number = rotation * Math.PI / 180;
var px:Number = x + Math.cos(angle) * _length;
var py:Number = y + Math.sin(angle) * _length;
return new Point( px, py );
}
}
internal class SegmentParam
{
public var length:int;
public var width : int;
public function SegmentParam( length:int, width:int ):void
{
this.length = length;
this.width = width;
}
}