forked from: GraphicsPathCommand使ったバージョン forked from: 布
布シミュをいじってみる by NOVO
* まだソース眺めただけ。
* ToDo 3Dにしてみたい
* ToDo 単位系をそろえる
* Done Fの計算が終わる前にXを動かしているのが偏りの原因っぽい
* ToDo せん断抵抗、角度抵抗用のJointを設定したい
* ToDo 微小時間でシミュレート
* ToDo 積分法を変えてみる?
* Done 初期化変更、必要ない変数も消す。描画方法もJointの描画だけでいいのでは?
* Doing 片方向のJointを両方向に変更
* Done 簡易ベクトルクラスに置き換え
* 以下オリジナルコメント
GraphicsPathCommandでラインを描画するバージョン。
* drawLine関数の中が違います。
*
* 本格的な布のシミュレーションではありません。
*
* ドラッグでマウスに一番近いポイントを移動させる。
* ctrlキー押しながらドラッグで固定。
* ダブルクリックで固定を解除。
/**
* 布シミュをいじってみる by NOVO
* まだソース眺めただけ。
* ToDo 3Dにしてみたい
* ToDo 単位系をそろえる
* Done Fの計算が終わる前にXを動かしているのが偏りの原因っぽい
* ToDo せん断抵抗、角度抵抗用のJointを設定したい
* ToDo 微小時間でシミュレート
* ToDo 積分法を変えてみる?
* Done 初期化変更、必要ない変数も消す。描画方法もJointの描画だけでいいのでは?
* Doing 片方向のJointを両方向に変更
* Done 簡易ベクトルクラスに置き換え
* 以下オリジナルコメント
*/
// forked from miniapp's GraphicsPathCommand使ったバージョン forked from: 布
/**
* GraphicsPathCommandでラインを描画するバージョン。
* drawLine関数の中が違います。
*
* 本格的な布のシミュレーションではありません。
*
* ドラッグでマウスに一番近いポイントを移動させる。
* ctrlキー押しながらドラッグで固定。
* ダブルクリックで固定を解除。
*/
package {
import flash.display.GraphicsPathCommand;
import flash.display.Sprite;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
[SWF(backgroundColor="0xFFFFFF", width="465", height="465", frameRate="60")]
public class Cloth_DrawPath extends Sprite {
public static const STAGE_WIDTH:uint = 465;
public static const STAGE_HEIGHT:uint = 465;
public function Cloth_DrawPath() {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private var _lineColor:uint = 0x000000;
private var _cols:uint = 16;//横の数
private var _rows:uint = 16;//縦の数
private var _diffX:uint = 10;
private var _diffY:uint = 10;
private var _isCtrlPress:Boolean = false;
private var _isMouseDown:Boolean = false;
private var _draggedPoint:Point;
private var _isFirst:Boolean = false;
//private var _numJoints:uint;
private var _joints:Vector.<Joint> = new Vector.<Joint>();
private var _points:Vector.<Point> = new Vector.<Point>();
//private var _pointsXs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_rows, true);
//private var _pointsYs:Vector.<Vector.<Point>> = new Vector.<Vector.<Point>>(_cols, true);
private var _vertices:Vector.<Number> = new Vector.<Number>();
private var _commands:Vector.<int> = new Vector.<int>();
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.scaleMode = StageScaleMode.NO_SCALE;
//stage.quality = StageQuality.MEDIUM;
stage.doubleClickEnabled = true;
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDwonHandler);
stage.addEventListener(MouseEvent.DOUBLE_CLICK, doubleClickHandler);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDonwHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
//putPoint();
//joint();
putPointAndJoint();
//上端2つを固定します。
//左端
//var point1:Point = _pointsXs[0][0];
var point1:Point = _points[0];
point1._position=new MyVector2D(100,10);
point1.isPinned = true;
//右端
//var point2:Point = _pointsXs[0][_rows - 1];
var point2:Point = _points[_rows - 1];
point2._position=new MyVector2D(STAGE_WIDTH - 100,10);
point2.isPinned = true;
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
/**
*
*
*/
private function putPointAndJoint():void
{
//00------01-------02
//| | |
//| | |
//| | |
//10------11-------12
//| | |
//| | |
//| | |
//20------21-------22
var clothWidth:Number = (_cols - 1) * _diffX;
var clothHeight:Number = (_rows - 1) * _diffY;
var startX:Number = (STAGE_WIDTH - clothWidth) / 2;
var startY:Number = (STAGE_HEIGHT - clothHeight) / 2;
//ポイントとジョイントを一気に配置したほうが楽なので
for(var y:uint=0;y<_rows;++y)
{
for(var x:uint=0;x<_cols;++x)
{
var point:Point=new Point();
_points.push(point);
point.name = String(y) + "-" + String(x);//デバッグ用
point._position=new MyVector2D(startX + _diffX * x,startY + _diffY * y);
//jointは片方向?
if(y>0)
{
//up
var pointUp:Point=_points[(y-1)*_cols+x];
_joints.push(new Joint(point,pointUp));
_joints.push(new Joint(pointUp,point));
}
if(x>0)
{
//left
var pointLeft:Point=_points[y*_cols+(x-1)];
_joints.push(new Joint(point,pointLeft));
_joints.push(new Joint(pointLeft,point));
}
}
}
trace("_poinits.length"+_points.length);
trace("_joints.length"+_joints.length);
_points.fixed=true;
_joints.fixed=true;
}
/**
* 一番カーソルに近いポイントを捜す。
*/
private function searchPoint():Point {
var lastMinDist:Number = Infinity;
var target:Point;
for each(var point:Point in _points) {
var pos:MyVector2D = point._position;
var m:MyVector2D=new MyVector2D(mouseX,mouseY);
var dist:Number = pos.subtract(m).length();
if (dist < lastMinDist) {
lastMinDist = dist;
target = point;
}
}
return target;
}
/**
* ポイント同士を繋ぐ線を書く
*/
private function drawLine():void {
graphics.clear();
graphics.lineStyle(1, _lineColor);
var dataIndex:uint = 0;
var commandIndex:uint = 0;
//二度描きしてしまう
for each(var joint:Joint in _joints)
{
var pointA:Point=joint._point;
var pointB:Point=joint._target;
_vertices[dataIndex++] = pointA._position.x;
_vertices[dataIndex++] = pointA._position.y;
_commands[commandIndex++] = GraphicsPathCommand.MOVE_TO;
_vertices[dataIndex++] = pointB._position.x;
_vertices[dataIndex++] = pointB._position.y;
_commands[commandIndex++] = GraphicsPathCommand.LINE_TO;
}
if(_isFirst){
_commands.fixed = _vertices.fixed = true;
_isFirst = false;
}
graphics.drawPath(_commands, _vertices);
}
private function enterFrameHandler(e:Event):void {
if (_isMouseDown) {
_draggedPoint._position.x = mouseX;
_draggedPoint._position.y = mouseY;
}
//フェーズを二つに分ける。力更新と位置更新
// update force
for each(var joint1:Joint in _joints) {
joint1.updateForce();
}
// update position
for each(var joint2:Joint in _joints) {
joint2.updatePosition();
}
drawLine();
}
private function keyDonwHandler(e:KeyboardEvent = null):void{
if(e.ctrlKey) _isCtrlPress = true;
}
private function keyUpHandler(e:KeyboardEvent = null):void{
_isCtrlPress = false;
}
private function doubleClickHandler(e:MouseEvent = null):void{
searchPoint().isPinned = false;
}
private function mouseDwonHandler(e:MouseEvent):void {
_isMouseDown = true;
_draggedPoint = searchPoint();
_draggedPoint.isDragging = true;
}
private function mouseUpHandler(e:MouseEvent):void {
_isMouseDown = false;
if (_isCtrlPress)
_draggedPoint.isPinned = true;
_draggedPoint.isDragging = false;
_draggedPoint = undefined;
}
}
}
//簡易ベクトルクラス
class MyVector2D
{
public var x:Number = 0.0;
public var y:Number = 0.0;
public function MyVector2D(inX:Number=0.0, inY:Number=0.0)
{
x = inX;
y = inY;
}
//+=
public function addTo(rhs:MyVector2D):MyVector2D
{
this.x += rhs.x;
this.y += rhs.y;
return this;
}
//+
public function add(rhs:MyVector2D):MyVector2D
{
return new MyVector2D(this.x + rhs.x, this.y + rhs.y);
}
//-=
public function subtractTo(rhs:MyVector2D):MyVector2D
{
this.x -= rhs.x;
this.y -= rhs.y;
return this;
}
//-
public function subtract(rhs:MyVector2D):MyVector2D
{
return new MyVector2D(this.x - rhs.x, this.y - rhs.y);
}
//*=
public function multiplyTo(rhs:Number):MyVector2D
{
this.x *= rhs;
this.y *= rhs;
return this;
}
//*
public function multiply(rhs:Number):MyVector2D
{
return new MyVector2D(this.x*rhs,this.y*rhs);
}
///=
public function divideTo(rhs:Number):MyVector2D
{
this.x /= rhs;
this.y /= rhs;
return this;
}
///
public function divide(rhs:Number):MyVector2D
{
return new MyVector2D(this.x/rhs,this.y/rhs);
}
public function length2():Number
{
return this.x * this.x + this.y * this.y;
}
public function length():Number
{
return Math.sqrt(length2());
}
}
class Joint {
public static var SPRING:Number = 0.03;
public static var FRICTION:Number = 0.97;
public static var GRAVITY:Number = 0.005;
public var _length:Number = 0.0;
public var _point:Point=null;
public var _target:Point=null;
public function Joint(point:Point, target:Point) {
_point=point;
_target = target;
var p1:MyVector2D = _point._position;
var p2:MyVector2D = _target._position;
_length = p1.subtract(p2).length();
var initD:MyVector2D = target._position.subtract(point._position);
var length:Number = initD.length();
var angle:Number = Math.atan2(initD.y, initD.x);
var t:MyVector2D =new MyVector2D( length * Math.cos(angle),length * Math.sin(angle));
//バネ運動させる関数
updateForce = function():void {
if (point.isDragging || point.isPinned)
return;
var d:MyVector2D = target._position.subtract(point._position).subtract(t);
point._force.addTo(d.multiply(Joint.SPRING));
point._force.y += GRAVITY;
}
updatePosition = function():void {
if (point.isDragging || point.isPinned)
return;
point._velocity.addTo(point._force.divide(point.mass));
point._force = new MyVector2D(0, 0);
point._position.addTo(point._velocity.multiplyTo(FRICTION));
// point.x += (point.vx *= FRICTION);
// point.y += (point.vy *= FRICTION);
}
}
public var updateForce:Function;
public var updatePosition:Function;
}
class Point {
public var name:String;
public var _position:MyVector2D = new MyVector2D();
// public var x:Number;
// public var y:Number;
public var _velocity:MyVector2D = new MyVector2D();
// public var vx:Number = 0;
// public var vy:Number = 0;
public var _force:MyVector2D = new MyVector2D();
// public var fx:Number=0;
// public var fy:Number=0;
public var mass:Number=1;//kari
public var isPinned:Boolean = false;
public var isDragging:Boolean = false;
}