UnityのJoint機能を使ってオブジェクトを繋げてみる

今回はJointの機能を使ってオブジェクトを繋げてみようと思います。

このJoint機能は相手側のRigidbodyにオブジェクトを繋げて
鎖やドア等を表現する事が出来ます。

Joint機能はRigidbodyに力や回転を加えると繋げている状態を解除する事が出来ます。

解除されるとアタッチされていたJointコンポーネント自体が削除されます。
Joint解除の力の強さや回転もパラメータとして設定する事が出来ます。

スポンサーリンク

Jointさせるゲームオブジェクトを作成

今回は3つのCubeを作り元となるオブジェクトをCube1、それに繋がるCube2、Cube2に繋がるCube3という
構造でJointさせます。

ジョイント1

上のように3D Object→Cubeで3つ作り名前を変更します。

ジョイント2

それぞれのCubeにRigidbodyとHingeJointコンポーネントを取りつけます。
二つともAdd Component→Physicsから選択するとすぐ見つかります。

大元のCube1はUse Gravityのチェックを外し重力を働かせないようにしておきます。
(使いどころによって設定は変わってきます)

大元なのでHingeJointが接続するRigidbodyには何も設定しません。
Anchorは繋がっている位置を指定し、ここの部分から動きます。

ジョイント5

上の茶色い矢印がAnchorの位置になります。

Axisは軸となる方向を指定します。
上の画像では、Xが1となっているので、ワールド座標のX軸で回転して動きます。

Use Springにチェックを入れます。Damperの数値を1にします。
Damperはオブジェクトの速さを低下させるパラメータ値です。
これが設定されていないと永遠に動き続けます。

Break ForceはJointを解除する力
Break TorqueはJointを解除する回転

を設定します。

Motorは自動で力を加える時に使うみたい?、Limitは回転の制限値を設定するものです。
今回の場合は、主人公がCubeにぶつかった時に力を加えるのと、銃で撃った時に力を加えます。
それ以外で力を加えたくないので、Motorは使いません。

SpringとMotorは同時に使えない為、両方にチェックを入れるとMotorが上書きされSpringが無効になるみたいです。

ジョイント4

上はCube2のHingeJointです。Connected BodyにはCube1のRigidbodyを設定します。

同様にCube3のHingeJointのConnected BodyにはCube2を設定します。

Cube2、Cube3のRigidbodyはUse Gravityのチェックを入れておきます。

これでCube2、Cube3のJointが外れた時に重力が働くので落下して転がります。

ジョイント3

上が設定して位置を調整した状態です。
上からCube1、Cube2、Cube3となっています。

主人公がこのCube達にぶつかると上の画像の青い矢印の方向に動きます。
(青矢印は説明の為に言及してますが、ワールド座標で言うとX軸の方向に動きます)

Cubeには新しいレイヤーFallObj、TagにBlockを設定しておきます。(名前はなんでもいいです)
これでCubeとJointの準備が終わったので、次は主人公がCubeに力を加える処理と、銃を撃った時に力を加える処理を追加します。

スクリプトから力を加えジョイント機能を確かめる

まずは主人公がCubeに力を加える為の処理を追加します。

新しいスクリプトJointTestを作成し、CharacterControllerが設定されている主人公にスクリプトを追加します。
Rigidbodyでキャラクターを動かしている場合は当たり判定にOnCollisionEnter等を使う必要があります。

OnControllerColliderHitはCharacterControllerが設定されているキャラクターが他のColliderを持っているオブジェクトとぶつかった時に呼ばれる関数です。

ぶつかったオブジェクトのタグを調べBlockであったら、ぶつかった相手のゲームオブジェクトに設定されているRigidbodyを取得し、それにぶつかった面の反対の方向に力を加えます。
transform.forwardでも良さそうな感じがしますが、これだと後ろ向きに当たった時に主人公側に力が加わりおかしくなります。
(後ろ向きで当たったのに、主人公の後ろにまとわりつく感じになります)

ぶつかった面の角度はcol.normalで取得出来ます。
加える力はJoint解除に関係してきますので、適当な数値を設定してください。

col.collider.gameObject.GetComponent.<Rigidbody>().AddForce(-col.normal * 100);は
col.collider.attachedRigidbody.AddForce(-col.normal * 100);

でも同じです。

また今回のサンプルスクリプトではBlockタグに設定されているゲームオブジェクトに必ずRigidbodyが設定されている事が条件になります。
本来であればRigidbodyが設定されているかどうか調べ、設定されていなければRigidbodyを追加する必要があります。

次は銃を撃った時の処理です。

銃を撃った時の処理に追加します。
FallObjレイヤーが設定されたオブジェクトに当たった時は当たった相手のRigidbodyに力を加えます。
銃の場合は主人公が向いている方向に力を加えるようにします。

これで処理が完成したのでUnityの実行ボタンを押して確認してみます。

ジョイント6

なぜか容量が大きくなったので画質を落としました。
主人公がぶつかると鎖のように振り子運動します。連続して当たるとJointが解除されます。
容量の関係で見れませんが、時間とともに振り子運動が小さくなり止まります。

ジョイント7

銃を撃って見ると、Jointが解除されコンポーネントのHingeJointが削除され、ただの1つのゲームオブジェクトになります。

これでJointを使ってオブジェクトを繋げてみる事が出来ました。
Jointが解除されるとコンポーネント自体が削除されます。

これで鎖やドア等を繋げて処理する事が出来るようになります。
Jointを解除したくない場合はBreak ForceとBreak TorqueにInfinityを設定すると解除されないようになります。

Joint機能は撃ち落とせる看板とか木にぶら下がったアイテムを落とすと言った機能を作りたい時に便利かもしれません。

UnityのJoint機能を使って木にアイテムを吊るし撃ち落とす
Unityのジョイント機能を使って木にアイテムを吊るして、それを銃で撃ち落とせるようにします

も参考にしてください。