簡易物理計算
簡易物理エンジン
箱の四隅はクリックでつまんで動かせます。
※激しく動かすとすぐに箱はこわれますw
箱同士の判定などは入れていないので、とりあえず場外判定のみ入ってます。
※変形した箱を2つ追加しました。
/**
* Copyright okoi ( http://wonderfl.net/user/okoi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/prrJ
*/
//
// 簡易物理エンジン
// 箱の四隅はクリックでつまんで動かせます。
// ※激しく動かすとすぐに箱はこわれますw
// 箱同士の判定などは入れていないので、とりあえず場外判定のみ入ってます。
//
// ※変形した箱を2つ追加しました。
//
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.text.TextField;
[SWF(width="465", height="465", backgroundColor="0x000000", frameRate="60")]
/***********************************************************************
* メインクラス
* @author okoi
*/
public class Main extends Sprite
{
private var pathList:Array = new Array();
private var jointList:Array = new Array(); // 固定用
private var jointList2:Array = new Array();
private var jointList3:Array = new Array();
private var grabid:int = -1;
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);
// entry point
addPath( 465/2-20, 465/2-20, pathList );
addPath( 465/2+20, 465/2-20, pathList );
addPath( 465/2+20, 465/2+20, pathList );
addPath( 465 / 2 - 20, 465 / 2 + 20, pathList );
addPath( 465/2-130, 465/2-130, pathList );
addPath( 465/2-80, 465/2-130, pathList );
addPath( 465/2-80, 465/2-80, pathList );
addPath( 465/2-130, 465 / 2 - 80, pathList );
addPath( 465/2+40, 465/2+40, pathList );
addPath( 465/2+80, 465/2+40, pathList );
addPath( 465/2+80, 465/2+80, pathList );
addPath( 465/2+40, 465 / 2 + 80, pathList );
// 固定用
addJoint( 0, 1, 0.5, jointList, pathList );
addJoint( 1, 2, 0.5, jointList, pathList );
// addJoint( 2, 3, 0.5, jointList, pathList );
// addJoint( 3, 0, 0.5, jointList, pathList );
addJoint( 0, 2, 0.5, jointList, pathList );
addJoint( 1, 3, 0.5, jointList, pathList );
addJoint( 4, 5, 0.5, jointList2, pathList );
addJoint( 5, 6, 0.5, jointList2, pathList );
addJoint( 6, 7, 0.5, jointList2, pathList );
addJoint( 7, 4, 0.5, jointList2, pathList );
addJoint( 8, 9, 0.5, jointList3, pathList );
addJoint( 9, 10, 0.5, jointList3, pathList );
addJoint( 10, 11, 0.5, jointList3, pathList );
addJoint( 11, 8, 0.5, jointList3, pathList );
addJoint( 8, 10, 0.5, jointList3, pathList );
addJoint( 9, 11, 0.5, jointList3, pathList );
addEventListener( Event.ENTER_FRAME, EnterFrame );
stage.addEventListener(MouseEvent.MOUSE_DOWN, GrabPath );
stage.addEventListener(MouseEvent.MOUSE_UP, ReleasePath );
stage.addEventListener(MouseEvent.MOUSE_OUT, ReleasePath );
}
private function EnterFrame(event:Event) : void {
var i:int = 0;
var j:PathJoint;
var path:Path;
// パスの先頭をマウスと合わせる
if ( grabid != -1 )
{
pathList[grabid]._x = stage.mouseX;
pathList[grabid]._y = stage.mouseY;
}
for each ( path in pathList ) path.Move( 0, 0.1 );
for ( var ct:int = 0; ct < 20; ct ++ )
{
// 1
for ( i = 0; i < jointList.length; i++ ) jointList[i].Calc();
for ( i = jointList.length - 1; i >= 0; i-- ) jointList[i].Calc();
// 2
for ( i = 0; i < jointList2.length; i++ ) jointList2[i].Calc();
for ( i = jointList2.length - 1; i >= 0; i-- ) jointList2[i].Calc();
// 3
for ( i = 0; i < jointList3.length; i++ ) jointList3[i].Calc();
for ( i = jointList3.length - 1; i >= 0; i-- ) jointList3[i].Calc();
for each ( path in pathList ) path.Calc(stage);
}
graphics.clear();
graphics.beginFill( 0x000000 );
graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
graphics.endFill( );
graphics.lineStyle( 1, 0xFF0000 );
for each( j in jointList ) j.DrawSprite( this );
for each( j in jointList2 ) j.DrawSprite( this );
for each( j in jointList3 ) j.DrawSprite( this );
for each( var p:Path in pathList )
{
if ( p._id == grabid ) p.DrawSprite( this, 0xFFFF00 );
else p.DrawSprite( this );
}
graphics.lineStyle( 1, 0xFFFFFF );
graphics.moveTo( 0, 400 );
graphics.lineTo( stage.stageWidth, 400 );
}
/**
* パスを掴んだかどうかの判定を行う
* @param e
*/
private function GrabPath(e:MouseEvent):void
{
var len:uint = pathList.length;
var p:Path;
for ( var i:uint = 0; i < len; i++ )
{
p = pathList[i];
if ( (e.stageX - p._x) * (e.stageX - p._x) + (e.stageY - p._y) * (e.stageY - p._y) < 25 )
{
grabid = i;
return;
}
}
}
private function ReleasePath(e:MouseEvent):void
{
grabid = -1;
}
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
import flash.display.Sprite;
import flash.display.Stage;
/**
* パス追加処理
* @param _x
* @param _y
* @param list
*/
function addPath(_x:Number, _y:Number, list:Array):void
{
var id:uint = list.length;
var path:Path = new Path( id, null, _x, _y );
list.push( path );
}
/**
* パスとパスの結合要素を追加
* @param start
* @param end
* @param ratio startパスに掛かる力
* @param jList 結合要素リスト
* @param pList パス要素リスト
*/
function addJoint(start:int, end:int, ratio:Number, jList:Array, pList:Array):void
{
jList.push( new PathJoint( null, pList[start], pList[end], ratio ) );
}
/***************************************************************************
* パスクラス
*/
class Path {
private var _parent:Sprite;
public var _x:Number;
public var _y:Number;
public var _id:int;
public var _prevX:Number;
public var _prevY:Number;
public var _moveX:Number = 0;
public var _moveY:Number = 0;
public function Path(__id:int, _p:Sprite, __x:Number, __y:Number) {
_parent = _parent;
_prevX = _x = __x;
_prevY = _y = __y;
_id = __id;
}
public function DrawSprite(_sp:Sprite=null, _col:uint = 0xFF0000):void
{
if ( _sp == null )
{
if ( _parent == null ) return;
_sp = _parent;
}
_sp.graphics.lineStyle(3, _col);
_sp.graphics.drawCircle(_x, _y, 5);
}
// おもに場外判定
public function Calc(stage:Stage):void
{
if ( _y < 0 )
{
_x += (_prevX - _x) * 0.02;
_y = 0;
_prevY = 0;
_moveY = 0;
}
if ( _y >= 400 )
{
_x += (_prevX - _x) * 0.02;
_y = 400;
_prevY = 400;
_moveY = 0;
}
if ( _x <= 0 )
{
_x = 0;
_prevX = 0;
_moveX = 0;
}
if ( _x >= stage.stageWidth )
{
_x = stage.stageWidth;
_prevX = stage.stageWidth;
_moveX = 0;
}
}
public function Move(mx:Number, my:Number):void
{
_moveX = (_x - _prevX) + mx;
_moveY = (_y - _prevY) + my;
_prevX = _x;
_prevY = _y;
_x += _moveX;
_y += _moveY;
}
}
/***************************************************************************
* パスとパスを繋げるクラス
*/
class PathJoint {
private var _parent:Sprite;
private var _Start:Path;
private var _End:Path;
private var _defLength:Number;
private var _ratio:Number; // _Startに掛かる力
public function PathJoint (_p:Sprite, _sp:Path, _ep:Path, _r:Number = 0.5) {
_parent = _p;
_Start = _sp;
_End = _ep;
_defLength = Math.sqrt( (_ep._x - _sp._x) * (_ep._x - _sp._x) + (_ep._y - _sp._y) * (_ep._y - _sp._y) );
_ratio = _r;
}
/**
* パス間の距離が初期状態と変わっていたら、パスの座標にその差分を増減させて、パス間の距離を一定に保つ
*/
public function Calc() : void {
var vecX:Number = _End._x - _Start._x;
var vecY:Number = _End._y - _Start._y;
var length:Number = Math.sqrt( vecX * vecX + vecY * vecY );
// パスの方向ベクトル(正規化)
var nx:Number = vecX / length;
var ny:Number = vecY / length;
if ( _defLength == length )
{
}else
{
length = _defLength;
nx *= length;
ny *= length;
// 距離の差分をパスの座標に反映させる
_Start._x += (vecX - nx) * _ratio;
_Start._y += (vecY - ny) * _ratio;
_End._x -= (vecX - nx) * (1-_ratio);
_End._y -= (vecY - ny) * (1-_ratio);
}
}
public function DrawSprite(_sp:Sprite):void
{
if ( _sp == null )
{
if ( _parent == null ) return;
_sp = _parent;
}
_sp.graphics.lineStyle(3, 0xFF0000);
_sp.graphics.moveTo(_Start._x, _Start._y);
_sp.graphics.lineTo(_End._x, _End._y);
}
}