Physics2DのCreateRagdollScene
PS Suite SDKの話。
Physics2Dのサンプルとしてある、Physics2DSample。
その中の、
CreateRagdollScene(Ragdollの基本的な生成方法を示したサンプルシーンです。)
について。
[Tips and notice]
まず全文。
This sample shows the way to create very simple ragdoll style object.
Ragdoll is composed of many primitives. (boxes and spheres)
You can determine which parts has collision detection inside one ragdoll by AddIgnorePair(...).
This is more convenient to construct the ragdoll compared with usual collision filter or group filter.But should be care about the fact that a lot of ignorePair makes the performance of broadphase become worse.
And once that the interpenetration happens, then it is difficult for the ragdoll to restore the original relative position
if there are a lot of ignorePair inside the ragdoll.
(interpenetration free means that it is also easy for the ragdoll to restore the original position
because there is no collision detection and it is free for any parts of the ragdoll to go forward and go back.)
google翻訳を駆使した意訳(間違ってるかもしれないので注意を。)
このサンプルでは簡単なラグドールの作成の方法を紹介します。
ラグドールは多くのプリミティブで構成されます。
AddIgnorePair(..)を使って、ラグドール内でどこに衝突検出を持つのか決めることが可能です。
この方法の方が、Filterを使うよりもラグドール作成において便利です。しかし、多くのignorePairはパフォーマンスを悪くするので気を付けてください。
また、ignorePairを使用し、万一ラグドールがこんがらがってしまったとき、元に戻るのが困難ですので注意してください。
(衝突検出をけせば、衝突することがないので重なってもこんがらがることがないし、元に簡単に戻ります。)
作成手順
- PhysicsShapeの作成
- 頭と体
- 左上部
- 右上部
- 左下部
- 右下部
- 一部の衝突を消す
PhysicsShapeの作成
151行目から
// body center Vector2 body_width = new Vector2(2.0f, 2.5f); sceneShapes[4] = new PhysicsShape(body_width); // head float head_width = 1.5f; sceneShapes[5] = new PhysicsShape(head_width); // arm 1, 2 Vector2 arm_width = new Vector2(1.5f, 0.75f); sceneShapes[6] = new PhysicsShape(arm_width); // hand float hand_width = 0.75f; sceneShapes[7] = new PhysicsShape(hand_width); // leg 1, 2 Vector2 leg_width = new Vector2(0.75f, 2.0f); sceneShapes[8] = new PhysicsShape(leg_width);
PhysicsBodyの作成
頭と体を作成し、Jointでつなげる。
219行目から
// create body Vector2 center_pos = new Vector2(-10.0f + 20.0f * i, 5.0f); sceneBodies[numBody] = new PhysicsBody(sceneShapes[4], 5.0f); sceneBodies[numBody].position = center_pos; //一部省略 // create head sceneBodies[numBody] = new PhysicsBody(sceneShapes[5], 1.0f); sceneBodies[numBody].position = center_pos + new Vector2(0.0f, body_width.Y) + new Vector2(0, head_width); //一部省略 // creat joint between body and head bodyA = sceneBodies[body_index]; bodyB = sceneBodies[head_index]; sceneJoints[numJoint] = new PhysicsJoint(bodyA, bodyB, bodyB.position + new Vector2(0.0f, -head_width), (uint)body_index, (uint)head_index); sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f); //移動はしない sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f); sceneJoints[numJoint].angleLim = 1; sceneJoints[numJoint].angleLower = PhysicsUtility.GetRadian(-10.0f); //10度の回転を許可 sceneJoints[numJoint].angleUpper = PhysicsUtility.GetRadian(10.0f); numJoint++;
左上部
247行目から。
arm1(肩から肘)、arm2(肘から手首)、handを作成しJointでつなげる。
// create left arm1 sceneBodies[numBody] = new PhysicsBody(sceneShapes[6], 1.0f); sceneBodies[numBody].position = center_pos + new Vector2(-body_width.X, 0.5f*body_width.Y) + new Vector2(-arm_width.X, 0.0f); //一部省略 // creat joint between body and left arm1 体とくっつける bodyA = sceneBodies[body_index]; bodyB = sceneBodies[larm1_index]; sceneJoints[numJoint] = new PhysicsJoint(bodyA, bodyB, bodyB.position+ new Vector2(+arm_width.X, 0.0f), (uint)body_index, (uint)larm1_index); sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f); //移動はしない sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f); sceneJoints[numJoint].angleLim = 1; sceneJoints[numJoint].angleLower = PhysicsUtility.GetRadian(-45.0f); //45度の回転を許可 sceneJoints[numJoint].angleUpper = PhysicsUtility.GetRadian(45.0f); numJoint++; // create left arm2 sceneBodies[numBody] = new PhysicsBody(sceneShapes[6], 1.0f); sceneBodies[numBody].position = center_pos + new Vector2(-body_width.X, 0.5f*body_width.Y) + new Vector2(-arm_width.X, 0.0f) + new Vector2(-2.0f*arm_width.X, 0.0f); //一部省略 // creat joint between left arm1 and left arm2 腕同士をくっつける bodyA = sceneBodies[larm1_index]; bodyB = sceneBodies[larm2_index]; sceneJoints[numJoint] = new PhysicsJoint(bodyA, bodyB, 0.5f*(bodyA.position + bodyB.position), (uint)larm1_index, (uint)larm2_index); sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f); //移動はしない sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f); sceneJoints[numJoint].angleLim = 1; sceneJoints[numJoint].angleLower = PhysicsUtility.GetRadian(-45.0f); //10度の回転を許可 sceneJoints[numJoint].angleUpper = PhysicsUtility.GetRadian(45.0f); numJoint++; // create left hand sceneBodies[numBody] = new PhysicsBody(sceneShapes[7], 1.0f); sceneBodies[numBody].position = center_pos + new Vector2(-body_width.X, 0.5f*body_width.Y) + new Vector2(-4.0f*arm_width.X, 0.0f) + new Vector2(-hand_width, 0.0f); //一部省略 // creat joint between left arm2 and left hand 腕と手をくっつける bodyA = sceneBodies[larm2_index]; bodyB = sceneBodies[lhand_index]; sceneJoints[numJoint] = new PhysicsJoint(bodyA, bodyB, bodyB.position + new Vector2(hand_width, 0), (uint)larm2_index, (uint)lhand_index); sceneJoints[numJoint].axis1Lim = new Vector2(1.0f, 0.0f); //移動はしない sceneJoints[numJoint].axis2Lim = new Vector2(0.0f, 1.0f); sceneJoints[numJoint].angleLim = 1; sceneJoints[numJoint].angleLower = PhysicsUtility.GetRadian(-10.0f); //10度の回転を許可 sceneJoints[numJoint].angleUpper = PhysicsUtility.GetRadian(10.0f); numJoint++;
右上部
左下部
右下部
内容は違っても方法は一緒なので省略。
一部の衝突を消す
PhysicsScene.AddIgnorePairを使用して衝突検出を消す
void AddIgnorePair (uint index1, uint index2)
衝突を無視するペアをリストに加える
index1 剛体ペアの一方 index2 剛体ペアのもう一方
まず左のラグドール。
449行目から。
AddIgnorePair((uint)body_index, (uint)head_index); //体・頭 AddIgnorePair((uint)body_index, (uint)rarm1_index); //体・右腕1 AddIgnorePair((uint)rarm1_index, (uint)rarm2_index); //右腕1・右腕2 AddIgnorePair((uint)rarm2_index, (uint)rhand_index); //右腕2・右手 AddIgnorePair((uint)body_index, (uint)larm1_index); //左上部で上と一緒 AddIgnorePair((uint)larm1_index, (uint)larm2_index); AddIgnorePair((uint)larm2_index, (uint)lhand_index); AddIgnorePair((uint)body_index, (uint)rleg1_index); //体・右足1 AddIgnorePair((uint)rleg1_index, (uint)rleg2_index); //右足1・右足2 AddIgnorePair((uint)body_index, (uint)lleg1_index); //左下部で上と一緒 AddIgnorePair((uint)lleg1_index, (uint)lleg2_index);
この状態では、足同士の判定衝突は残ったまま。
強い力がかかった時に、万一足が絡まってしまうと、元に戻るのは困難。
真ん中のラグドール
469行目から。
sceneBodies[body_index].collisionFilter = 1; sceneBodies[head_index].collisionFilter = 1; sceneBodies[larm1_index].collisionFilter = 1; sceneBodies[larm2_index].collisionFilter = 1; sceneBodies[lhand_index].collisionFilter = 1; sceneBodies[rarm1_index].collisionFilter = 1; sceneBodies[rarm2_index].collisionFilter = 1; sceneBodies[rhand_index].collisionFilter = 1; sceneBodies[lleg1_index].collisionFilter = 1; sceneBodies[lleg2_index].collisionFilter = 1; sceneBodies[rleg1_index].collisionFilter = 1; sceneBodies[rleg2_index].collisionFilter = 1;
collisionFilterをすべてのパーツに適用。
体の中で衝突はしない。
比較的安定するようになる。
最後の右のラグドール
487行目から。
衝突はすべて行われる。
そのせいでとても不安定。テストのためだけに使う。