ConstraintWorld ライブラリ( 仮 )
ばね制約効果開発テスト
参考
BONKURA BLOG - イージングとバネ運動に関する公式
http://blog.bonkura.jp/formula05.html
kazy - SPRING TO MOUSE
http://wonderfl.kayac.com/code/3c6818a68120935d5373f3b07c17b0acd22c0034
...
@author tkinjo
/**
* Copyright tkinjo ( http://wonderfl.net/user/tkinjo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/ot65
*/
// forked from tkinjo's FollowConstraint
// forked from tkinjo's Dot
package
{
/**
* ConstraintWorld ライブラリ( 仮 )
*
* ばね制約効果開発テスト
*
* 参考
*
* BONKURA BLOG - イージングとバネ運動に関する公式
* http://blog.bonkura.jp/formula05.html
*
* kazy - SPRING TO MOUSE
* http://wonderfl.kayac.com/code/3c6818a68120935d5373f3b07c17b0acd22c0034
*/
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Vector3D;
[SWF(width="465", height="465", frameRate="60", backgroundColor="0xffffff")]
/**
* ...
* @author tkinjo
*/
public class Main extends Sprite
{
private var constraintWorld:ConstraintWorld;
private var mousePointer:Particle;
/**
*
*/
public function Main()
{
constraintWorld = new ConstraintWorld( 0.9 );
mousePointer = new Particle( mouseX, mouseY );
//*
var preCircle:Circle;
for ( var i:Number = 0; i < 5; i++ ) {
var circle:Circle = new Circle();
circle.friction = 0.9;
constraintWorld.addParticle( circle );
if( i == 0 )
constraintWorld.addConstraint( new SpringConstraint( mousePointer, circle, 0.1, 20 ) );
else
constraintWorld.addConstraint( new SpringConstraint( preCircle, circle, 0.1, 20 ) );
addChild( circle );
preCircle = circle;
}
//*/
addEventListener( Event.ENTER_FRAME, enterFrameHandler );
}
/**
*
* @param event
*/
private function enterFrameHandler( event:Event ):void {
mousePointer.x = mouseX;
mousePointer.y = mouseY;
constraintWorld.step();
}
}
}
/**
*
*/
//class SpringConstraint extends Constraint implements IConstraint { // 拡張しようとするとエラーでる…
class SpringConstraint implements IConstraint {
private var constraint:Constraint;
public function get particle1():IParticle { return constraint.particle1 };
public function set particle1(value:IParticle):void { constraint.particle1 = value };
public function get particle2():IParticle { return constraint.particle2 };
public function set particle2(value:IParticle):void { constraint.particle2 = value; };
public function get allowedDistance():Number { return constraint.allowedDistance; }
public function set allowedDistance(value:Number):void { constraint.allowedDistance = value; }
public function get minDistance():Number { return constraint.minDistance; }
public function set minDistance(value:Number):void { constraint.minDistance = value; }
public function get maxDistance():Number { return constraint.maxDistance; }
public function set maxDistance(value:Number):void { constraint.maxDistance = value; }
/**
* 弾性
*/
public var elasticity:Number;
/**
*
* @param particle1
* @param particle2
* @param stiffness
*/
public function SpringConstraint( particle1:IParticle, particle2:IParticle, elasticity:Number = 0.1, allowedDistance:Number = 0, minDistance:Number = -1, maxDistance:Number = -1 ) {
//super( particle1, particle2 );
constraint = new Constraint( particle1, particle2, allowedDistance, minDistance, maxDistance );
this.elasticity = elasticity;
}
/**
* 解析
*/
//override public function resolve():void {
public function preApply( threeD:Boolean ):void {
constraint.particle2.vx += ( constraint.distance - allowedDistance ) * -Math.cos( constraint.angle ) * elasticity;
constraint.particle2.vy += ( constraint.distance - allowedDistance ) * -Math.sin( constraint.angle ) * elasticity;
}
/**
*
* @param threeD
*/
public function apply( threeD:Boolean ):void {
// super.apply( threeD );
constraint.apply( threeD );
}
}
import flash.display.Sprite;
/**
*
*/
class Circle extends Sprite implements IParticle {
/** --------------------------------------------------
* 半径
*/
public function get radius():Number { return _radius; }
/**
* @private
*/
public function set radius(value:Number):void
{
_radius = value;
draw();
}
private var _radius:Number;
/** --------------------------------------------------
* 色
*/
public function get color():uint { return _color; }
/**
* @private
*/
public function set color(value:uint):void
{
_color = value;
draw();
}
private var _color:uint;
/**
* x 方向の速度
*/
public function get vx():Number { return _vx; }
public function set vx(value:Number):void { _vx = value; }
private var _vx:Number = 0;
/**
* y 方向の速度
*/
public function get vy():Number { return _vy; }
public function set vy(value:Number):void { _vy = value; }
private var _vy:Number = 0;
/**
* z 方向の速度
*/
public function get vz():Number { return _vz; }
public function set vz(value:Number):void { _vz = value; }
private var _vz:Number = 0;
/**
* z 方向の速度
*/
public function get friction():Number { return _friction; }
public function set friction(value:Number):void { _friction = value; }
private var _friction:Number = 1;
/**
*
* @param radius
* @param color
*/
public function Circle( radius:Number = 5, color:uint = 0 ) {
this.radius = radius;
this.color = color;
}
/**
*
*/
public function draw():void {
graphics.clear();
graphics.beginFill( color );
graphics.drawCircle( 0, 0, _radius );
}
}
/**
*
*/
interface IConstraint {
function get particle1():IParticle;
function set particle1(value:IParticle):void;
function get particle2():IParticle;
function set particle2(value:IParticle):void;
function get allowedDistance():Number;
function set allowedDistance(value:Number):void;
function get minDistance():Number;
function set minDistance(value:Number):void;
function get maxDistance():Number;
function set maxDistance(value:Number):void;
function preApply( threeD:Boolean ):void;
function apply( threeD:Boolean ):void;
}
/**
*
*/
class Constraint implements IConstraint {
/**
*
*/
public function get particle1():IParticle { return _particle1; }
public function set particle1(value:IParticle):void { _particle1 = value; }
protected var _particle1:IParticle;
/**
*
*/
public function get particle2():IParticle { return _particle2; }
public function set particle2(value:IParticle):void { _particle2 = value; }
protected var _particle2:IParticle;
/**
*
*/
public function get allowedDistance():Number { return _allowedDistance; }
public function set allowedDistance(value:Number):void { _allowedDistance = value; }
private var _allowedDistance:Number;
/**
*
*/
public function get minDistance():Number { return _minDistance; }
public function set minDistance(value:Number):void { _minDistance = value; }
private var _minDistance:Number;
/**
*
*/
public function get maxDistance():Number { return _maxDistance; }
public function set maxDistance(value:Number):void { _maxDistance = value; }
private var _maxDistance:Number;
/**
*
* @param particle1
* @param particle2
*/
public function Constraint( particle1:IParticle, particle2:IParticle, allowedDistance:Number = 0, minDistance:Number = -1, maxDistance:Number = -1 ) {
_particle1 = particle1;
_particle2 = particle2;
_allowedDistance = allowedDistance;
_minDistance = minDistance;
_maxDistance = maxDistance;
}
/**
*
*/
//protected function get dx():Number {
public function get dx():Number {
return _particle2.x - _particle1.x;
}
/**
*
*/
//protected function get dy():Number {
public function get dy():Number {
return _particle2.y - _particle1.y;
}
/**
*
*/
public function get distance():Number {
return Math.sqrt( dx * dx + dy * dy );
}
/**
*
*/
public function get angle():Number {
return Math.atan2(dy, dx);
}
/**
* 解析
*/
public function preApply( threeD:Boolean ):void {
}
/**
* 解析
*/
public function apply( threeD:Boolean ):void {
// 一定の距離をあける
if( 0 <= minDistance && distance < minDistance ) {
particle2.x = particle1.x + minDistance * Math.cos( angle );
particle2.y = particle1.y + minDistance * Math.sin( angle );
// 一定の距離以上離れさせない
} else if ( 0 <= maxDistance && distance > maxDistance ) {
particle2.x = particle1.x + maxDistance * Math.cos( angle );
particle2.y = particle1.y + maxDistance * Math.sin( angle );
}
}
}
/**
*
*/
interface IParticle {
function get x():Number;
function set x(value:Number):void;
function get y():Number;
function set y(value:Number):void
function get z():Number;
function set z(value:Number):void;
function get vx():Number;
function set vx(value:Number):void;
function get vy():Number;
function set vy(value:Number):void;
function get vz():Number;
function set vz(value:Number):void;
function get friction():Number;
function set friction(value:Number):void;
}
/**
*
*/
class Particle implements IParticle {
private var _x:Number;
public function get x():Number { return _x; }
public function set x(value:Number):void { _x = value; }
private var _y:Number;
public function get y():Number { return _y; }
public function set y(value:Number):void { _y = value; }
private var _z:Number;
public function get z():Number { return _z; }
public function set z(value:Number):void { _z = value; }
private var _vx:Number;
public function get vx():Number { return _vx; }
public function set vx(value:Number):void { _vx = value; }
private var _vy:Number;
public function get vy():Number { return _vy; }
public function set vy(value:Number):void { _vy = value; }
private var _vz:Number;
public function get vz():Number { return _vz; }
public function set vz(value:Number):void { _vz = value; }
private var _friction:Number;
public function get friction():Number { return _friction; }
public function set friction(value:Number):void { _friction = value; }
public function Particle( x:Number = 0, y:Number = 0, z:Number = 0, vx:Number = 0, vy:Number = 0, vz:Number = 0, friction:Number = 0 ):void {
_x = x;
_y = y;
_z = z;
_vx = vx;
_vy = vy;
_vz = vz;
_friction = friction;
}
}
import flash.geom.Vector3D;
/**
* ワールドクラス
*
* 重力や 3D など設定とパーティクルとそれらに適用される制約効果の管理
*/
class ConstraintWorld {
/**
* 摩擦係数
*/
public var friction:Number;
/**
* パーティクルに常にかかる力
*/
public var force:Vector3D;
/**
* 3D
*/
public var threeD:Boolean;
/**
* パーティクルの配列
*/
private var particles:Vector.<IParticle>;
/**
* 制約効果の配列
*/
private var constraints:Vector.<IConstraint>;
/**
* コンストラクタ
*/
public function ConstraintWorld( friction:Number = 1, force:Vector3D = null, threeD:Boolean = false ):void {
this.friction = friction;
if ( !force )
this.force = new Vector3D();
else
this.force = force;
this.threeD = threeD;
particles = new Vector.<IParticle>();
constraints = new Vector.<IConstraint>();
}
/**
*
*/
public function step():void {
// force の適用前の制約効果処理
constraints.forEach( function(item:IConstraint, index:int, vector:Vector.<IConstraint>):void {
item.preApply( threeD );
} );
// force の適用
if ( force ) {
particles.forEach( function(item:IParticle, index:int, vector:Vector.<IParticle>):void {
item.vx += force.x;
item.vy += force.y;
item.vz += force.z;
} );
}
// force の適用後の制約効果処理
constraints.forEach( function(item:IConstraint, index:int, vector:Vector.<IConstraint>):void {
item.apply( threeD );
} );
// 適用
particles.forEach( function(item:IParticle, index:int, vector:Vector.<IParticle>):void {
item.vx *= friction * item.friction;
item.vy *= friction * item.friction;
item.x += item.vx;
item.y += item.vy;
if( threeD )
item.vz *= friction * item.friction;
item.z += item.vz;
} );
}
/**
*
*/
public function addParticle( particle:IParticle ):IParticle {
particles.push( particle );
return particle;
}
/**
*
* @param particle
* @return
*/
public function removeParticle( particle:IParticle ):void {
particles.every( function( item:IParticle, index:int, array:Array ):Boolean {
if ( item == particle ) {
particles.splice( index, 1 );
return false;
}
return true;
} );
}
/**
*
*/
public function addConstraint( constraint:IConstraint ):IConstraint {
constraints.push( constraint );
return constraint;
}
/**
*
* @param constraint
* @return
*/
public function removeConstraint( constraint:IConstraint ):void {
constraints.every( function( item:IConstraint, index:int, array:Array ):Boolean {
if ( item == constraint ) {
constraints.splice( index, 1 );
return false;
}
return true;
} );
}
/**
*
* @param constraint
* @return
*/
public function removeConstraintAtParticle( particle:IParticle ):void {
constraints.every( function( item:IConstraint, index:int, array:Array ):Boolean {
if ( item.particle1 == particle || item.particle2 == particle ) {
constraints.splice( index, 1 );
return false;
}
return true;
} );
}
}