物理学をフラッシュで作成する必要がありましたが、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もちろん、うなじはまだ非常に若いです。 そして、例えば、眠りに落ちるオブジェクトにはいくつかの問題がありますが、彼の可能性は非常に大きいです。