フラッシュ上の物理学。 AS3のNapeでラグドールを作成する

画像

物理学をフラッシュで作成する必要がありましたが、1つの小さなニュアンスが必要でした。 ステージ上に10〜15個のレグドルを表示する必要がありました(知らない人のために。レグドルは人形です。人体の模倣)。 人気のあるBox2Dでこれを実装しようとすると、Box2Dで実行できないという残念な結論に至りました。 ちょっとしたグーグルが比較的新しいNape()エンジンを見つけました。 これは一般にこの問題を解決しました。

驚いたことに、私はハブでNapeの言及を見つけることができず、ハブでの作業の始まりを説明することにしました。

カットの下で、regdolの作成の説明、Box2DとNapeでの比較のための例、および例のソースコード。







プロジェクトはFlashDevelopで作成されます。 プロジェクト全体へのリンクを以下に示します。

Napeをダウンロードしてプロジェクトに接続するのは簡単なので、説明しません。



1.世界の創造。



最も重要な瞬間。 コンストラクターで、ライブラリローダーを登録する必要があります。

public function Main(): void

{

new Boot();

….........................

}




* This source code was highlighted with Source Code Highlighter .








public function Main(): void

{

new Boot();

….........................

}




* This source code was highlighted with Source Code Highlighter .












Napeの世界は、3つのクラスで説明されています。

UniformSpaceは、オブジェクトが眠れない世界です。

UniformSleepSpaceは、力が作用しなければオブジェクトが眠りに落ちる世界です。 これにより、プロセッサリソースが節約されます。

BruteSpaceは、オブジェクトが眠ることができない境界線のないスペースです。



理解できるように、最も一般的なのはUniformSleepSpaceです。 それに基づいてプロジェクトを構築します。

// .

var gravity:Vec2 = new Vec2(0, 250);

// . , .

var world:UniformSleepSpace = new UniformSleepSpace( new AABB(0,0, 800, 600), 25, gravity);




* This source code was highlighted with Source Code Highlighter .








// .

var gravity:Vec2 = new Vec2(0, 250);

// . , .

var world:UniformSleepSpace = new UniformSleepSpace( new AABB(0,0, 800, 600), 25, gravity);




* This source code was highlighted with Source Code Highlighter .












Box2Dとは異なり、Napeは物理的な世界と画面上の画像との間でスケーリングしません。 すべてはピクセルで計算されます。



世界の創造は終わりました。 どうやらこれについて複雑なことは何もない。



2.静的ボディを作成します。



私たちの場合、それは一つです-これは地球です。



静的プラットフォームを作成する

パラメーターでは、サイズ、空間内の位置、速度、およびボディのタイプへのポインターを示します(true-静的、false-動的)

physObject = Tools.createBox(400, 500, 700, 20, 0, 0, 0, true , Material.Steel);

world.addObject(physObject); //

addChild(physObject.graphic); //




* This source code was highlighted with Source Code Highlighter .








physObject = Tools.createBox(400, 500, 700, 20, 0, 0, 0, true , Material.Steel);

world.addObject(physObject); //

addChild(physObject.graphic); //




* This source code was highlighted with Source Code Highlighter .












Napeは、Material.SteelやMaterial.Woodなどのデフォルトマテリアルを追加しました。 これにより、プロトタイプ作成と開発が非常に容易になります。



また、Box2Dとは異なり、デフォルトのグラフィックを作成する必要はありません。 オブジェクトにはグラフィックプロパティがあります。 グラフィックをインストールしない場合、デフォルトのプリミティブが表示されます。



3.世界を立ち上げる。

世界を表示するには、ENTER_FRAMEハンドラーを作成し、その中のUniformSleepSpaceインスタンスのstep()メソッドを呼び出します。

シミュレートされた時間をパラメーターとして送信します(例:1 / 30.0)



この段階で、すでにプロジェクトを開始でき、1つのオブジェクトが画面に表示されます-地球。



4.ラグドールを作成します。



人形の体は次のようになります。



画像



人形の物理的なつながりは赤で強調表示されています。



物理エンジンをさらに使用して作業しやすくするために、アクターオブジェクトを作成します。これは、物理世界と表示された画像との間の接続として機能します。



public class Actor extends EventDispatcher

{

//

protected var _body:PhysObj;

// (, )

protected var _costume:DisplayObject;



public function Actor(myBody:PhysObj, myCostume:DisplayObject)

{

_body = myBody;

_costume = myCostume;



if (_body != null )

{

updateLook();

}

}



public function Update(): void

{

// , ,

if (!_body.sleep)

{

updateLook();

}

}



//

private function updateLook(): void

{

var PosX:Number = _body.px;

var PosY:Number = _body.py;

_costume.x = PosX * Main.SCALE;

_costume.y = PosY * Main.SCALE;

}



}




* This source code was highlighted with Source Code Highlighter .








public class Actor extends EventDispatcher

{

//

protected var _body:PhysObj;

// (, )

protected var _costume:DisplayObject;



public function Actor(myBody:PhysObj, myCostume:DisplayObject)

{

_body = myBody;

_costume = myCostume;



if (_body != null )

{

updateLook();

}

}



public function Update(): void

{

// , ,

if (!_body.sleep)

{

updateLook();

}

}



//

private function updateLook(): void

{

var PosX:Number = _body.px;

var PosY:Number = _body.py;

_costume.x = PosX * Main.SCALE;

_costume.y = PosY * Main.SCALE;

}



}




* This source code was highlighted with Source Code Highlighter .












クラスActorを展開して、人体の「Head」オブジェクトを作成しましょう



public class Head extends Actor

{

public var head:PhysObj;



[Embed(source = '../../../../lib/ragdol.swf' , symbol = 'Ragdoll' )]

public var _headSprite: Class;



public function Head(parent:DisplayObjectContainer , location:Point, dimension:Point, initVel:Point)

{

var radius:Number = dimension.y / 2;



// HEAD -------------------------------------------------------------------------------

var headSprite:Sprite = new _headSprite();

headSprite.scaleX = radius * 2 / headSprite.width;

headSprite.scaleY = radius * 2 / headSprite.height;

//

if (!Main.gebug) parent.addChild(headSprite);



//

head = Tools.createCircle(location.x, location.y, radius, 0, 0, 0, false , true , Main.RagdolMaterial);

//

Main.world.addObject(head);

parent.addChild(head.graphic);



//

super(head, headSprite);

}



}




* This source code was highlighted with Source Code Highlighter .








public class Head extends Actor

{

public var head:PhysObj;



[Embed(source = '../../../../lib/ragdol.swf' , symbol = 'Ragdoll' )]

public var _headSprite: Class;



public function Head(parent:DisplayObjectContainer , location:Point, dimension:Point, initVel:Point)

{

var radius:Number = dimension.y / 2;



// HEAD -------------------------------------------------------------------------------

var headSprite:Sprite = new _headSprite();

headSprite.scaleX = radius * 2 / headSprite.width;

headSprite.scaleY = radius * 2 / headSprite.height;

//

if (!Main.gebug) parent.addChild(headSprite);



//

head = Tools.createCircle(location.x, location.y, radius, 0, 0, 0, false , true , Main.RagdolMaterial);

//

Main.world.addObject(head);

parent.addChild(head.graphic);



//

super(head, headSprite);

}



}




* This source code was highlighted with Source Code Highlighter .












体のすべての部分は同じように記述されます。

スペースを節約するために、ここではすべての部分について説明しません。 それらはいろいろな形で見ることができます。



全身を記述するRagdollオブジェクトを作成します。 それらの間の接続。



public class Ragdol extends Actor

{

//

public var _actors:Array;

// .

private var pj:PivotJoint;



// . .

public var rost:Number = 200.0;



// . .



public function Ragdol(parent:DisplayObjectContainer , loc:Point, initVel:Point)

{

// . .

var maxBias:Number = 0.1;

var maxForce:Number = 1e+9;



// .



//

_actors.push( new Head(parent, new Point( head_x, head_y ), new Point(0, dhead), new Point(0, 0)));

_actors.push( new Torso1(parent, new Point( torso1_x, torso1_y ), new Point(ttorso, dtorso1), new Point(0, 0)));

_actors.push( new Torso2(parent, new Point( torso2_x, torso2_y ), new Point(ttorso, dtorso2), new Point(0, 0)));

_actors.push( new Torso3(parent, new Point( torso3_x, torso3_y ), new Point(ttorso, dtorso3), new Point(0, 0)));



_actors.push( new ArmLup(parent, new Point( l_arm_up_x, l_arm_up_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmLmid(parent, new Point( l_arm_low_x, l_arm_low_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmRup(parent, new Point( r_arm_up_x, r_arm_up_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmRmid(parent, new Point( r_arm_low_x, r_arm_low_y ), new Point(tarm, darm), new Point(0, 0)));



_actors.push( new LegLup(parent, new Point(l_leg_up_x, l_leg_up_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegLlow(parent, new Point(l_leg_low_x, l_leg_low_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegRup(parent, new Point(r_leg_up_x, r_leg_up_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegRlow(parent, new Point(r_leg_low_x, r_leg_low_y), new Point(tleg, dleg), new Point(0, 0)));



//

//Head to torso1

pj = new PivotJoint(_actors[0].head, _actors[1].torso1, new Vec2(head_x, head_y + dhead/2));

pj.maxBias = maxBias;

pj.maxForce = maxForce;

Main.world.addConstraint(pj);



// .

// . .



super( null , null );



}



}




* This source code was highlighted with Source Code Highlighter .








public class Ragdol extends Actor

{

//

public var _actors:Array;

// .

private var pj:PivotJoint;



// . .

public var rost:Number = 200.0;



// . .



public function Ragdol(parent:DisplayObjectContainer , loc:Point, initVel:Point)

{

// . .

var maxBias:Number = 0.1;

var maxForce:Number = 1e+9;



// .



//

_actors.push( new Head(parent, new Point( head_x, head_y ), new Point(0, dhead), new Point(0, 0)));

_actors.push( new Torso1(parent, new Point( torso1_x, torso1_y ), new Point(ttorso, dtorso1), new Point(0, 0)));

_actors.push( new Torso2(parent, new Point( torso2_x, torso2_y ), new Point(ttorso, dtorso2), new Point(0, 0)));

_actors.push( new Torso3(parent, new Point( torso3_x, torso3_y ), new Point(ttorso, dtorso3), new Point(0, 0)));



_actors.push( new ArmLup(parent, new Point( l_arm_up_x, l_arm_up_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmLmid(parent, new Point( l_arm_low_x, l_arm_low_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmRup(parent, new Point( r_arm_up_x, r_arm_up_y ), new Point(tarm, darm), new Point(0, 0)));

_actors.push( new ArmRmid(parent, new Point( r_arm_low_x, r_arm_low_y ), new Point(tarm, darm), new Point(0, 0)));



_actors.push( new LegLup(parent, new Point(l_leg_up_x, l_leg_up_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegLlow(parent, new Point(l_leg_low_x, l_leg_low_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegRup(parent, new Point(r_leg_up_x, r_leg_up_y), new Point(tleg, dleg), new Point(0, 0)));

_actors.push( new LegRlow(parent, new Point(r_leg_low_x, r_leg_low_y), new Point(tleg, dleg), new Point(0, 0)));



//

//Head to torso1

pj = new PivotJoint(_actors[0].head, _actors[1].torso1, new Vec2(head_x, head_y + dhead/2));

pj.maxBias = maxBias;

pj.maxForce = maxForce;

Main.world.addConstraint(pj);



// .

// . .



super( null , null );



}



}




* This source code was highlighted with Source Code Highlighter .












5.レドルの使用。



最も簡単なテストでは、マウスクリックハンドラーを追加します。

private function onClick(e:MouseEvent): void

{

_ragdolActors.push( new Ragdol( this , new Point(mouseX, mouseY), new Point(0, 0)));

}




* This source code was highlighted with Source Code Highlighter .








private function onClick(e:MouseEvent): void

{

_ragdolActors.push( new Ragdol( this , new Point(mouseX, mouseY), new Point(0, 0)));

}




* This source code was highlighted with Source Code Highlighter .












これにより、画面にregdolが追加されます。



物理的な世界が機能するために、更新ハンドラーについて説明します。



private function update(e:Event): void

{

//

world.step(timeStep);



//

for ( var i: int = 0; i < _ragdolActors.length; i++ ) {



for ( var r: int = 0; r < _ragdolActors[i]._actors.length; r++ ) {

_ragdolActors[i]._actors[r].Update();

}



}



}



* This source code was highlighted with Source Code Highlighter .








private function update(e:Event): void

{

//

world.step(timeStep);



//

for ( var i: int = 0; i < _ragdolActors.length; i++ ) {



for ( var r: int = 0; r < _ragdolActors[i]._actors.length; r++ ) {

_ragdolActors[i]._actors[r].Update();

}



}



}



* This source code was highlighted with Source Code Highlighter .










ラグドールを作成する最も簡単な例は終わりです。



次のリンクは例です。

Box2Dのレドル

solverit.ru/swf

うなじのレグドル

solverit.ru/swf2



両方の例のソースは、物理ライブラリが異なることを除いて同一です。 そのため、パフォーマンスの違いを視覚的に推定できます。



FlashDevelopのプロジェクトソース

solverit.ru/files/RagdollNape.zip



PSもちろん、うなじはまだ非常に若いです。 そして、例えば、眠りに落ちるオブジェクトにはいくつかの問題がありますが、彼の可能性は非常に大きいです。



All Articles