今回はJointの機能を使ってオブジェクトを繋げてみようと思います。
このJoint機能は相手側のRigidbodyにオブジェクトを繋げて鎖やドア等を表現する事が出来ます。
今回は3つのゲームオブジェクトをHingeJointで繋げ、主人公キャラクターでぶつかったり、銃を撃って撃ち落としたりしてジョイントの解除が出来るようにします。
↑のような感じの機能が作成出来ます。
元々連結させているゲームオブジェクトを力を加えて別個のゲームオブジェクトとしたい場合等に便利な機能ですね。
Joint機能はRigidbodyに力や回転を加えると繋げている状態を解除する事が出来ます。
解除されるとアタッチされていたJointコンポーネント自体が削除されます。
Joint解除の力の強さや回転もパラメータとして設定する事が出来ます。
Jointさせるゲームオブジェクトを作成
今回は3つのCubeを作り元となるオブジェクトをCube1、それに繋がるCube2、Cube2に繋がるCube3という
構造でJointさせます。
上のように3D Object→Cubeで3つ作り名前を変更します。
それぞれのCubeにRigidbodyとHingeJointコンポーネントを取りつけます。
二つともAdd Component→Physicsから選択するとすぐ見つかります。
Cube1は大元なのでHingeJointが接続するRigidbodyには何も設定しません。
Anchorは繋がっている位置を指定し、ここの部分から動きます。
上の茶色い矢印がAnchorの位置になります。
Axisは軸となる方向を指定します。
上の画像では、Xが1となっているので、ワールド座標のX軸で回転して動きます。
Use Springにチェックを入れるとバネのような挙動をします。
Springはターゲット位置に移動する為の力、Damperはオブジェクトのバネの力を低下させるパラメータ値、Target Positionはターゲットの角度です。
Use Motorにチェックを入れるとモーターを使用します。
Target Velocityはターゲットの速度で、ForceはTarget Velocityになるのに加える力、Free Spinにチェックを入れるとブレーキではなく加速のみに力を加えます。
Limitsは回転の制限値を設定するものです。
Break ForceはJointを解除する力
Break TorqueはJointを解除する回転
を設定します。
今回はCube1~3全てのBreakForceを200、BreakTorqueを200にします。
今回は、主人公がCubeにぶつかった時に力を加えるのと、銃で撃った時に力を加えます。
それ以外で力を加えたくないので、Motorは使いません。
SpringとMotorは同時に使えない為、両方にチェックを入れるとMotorが上書きされSpringが無効になるみたいです。
上はCube2のHingeJointです。Connected BodyにはCube1のRigidbodyを設定します。
同様にCube3のHingeJointのConnected BodyにはCube2を設定します。
Cube1、Cube2、Cube3のRigidbodyはUse Gravityのチェックを入れておきます。
これでCube1、Cube2、Cube3のJointが外れた時に重力が働くので落下して転がります。
上が設定して位置を調整した状態です。
上からCube1、Cube2、Cube3となっています。
主人公がこのCube達にぶつかると上の画像の青い矢印の方向に動きます。
(青矢印は説明の為に言及してますが、ワールド座標で言うとX軸の方向に動きます)
Cube1~3にはBlockレイヤーを設定しておきます。(名前はなんでもいいです)
これでCubeとJointの準備が終わったので、次は主人公がCubeに力を加える処理と、銃を撃った時に力を加える処理を追加します。
スクリプトから力を加えジョイント機能を確かめる
まずは主人公がCubeに力を加える為の処理を追加します。
新しいスクリプトAddForceCubeを作成し、CharacterControllerが設定されている主人公にスクリプトを追加します。
Rigidbodyでキャラクターを動かしている場合は当たり判定にOnCollisionEnter等を使う必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | using UnityEngine; using System.Collections; public class AddForceCube : MonoBehaviour { [SerializeField] private float addForcePower = 100f; // Blockレイヤーを持つゲームオブジェクトと接触したら力を加える void OnControllerColliderHit(ControllerColliderHit col) { if(col.gameObject.layer == LayerMask.NameToLayer ("Block")) { col.rigidbody.AddForce(-col.normal * addForcePower); } } } |
OnControllerColliderHitはCharacterControllerが設定されているキャラクターが他のColliderを持っているオブジェクトとぶつかった時に呼ばれるメソッドです。
ぶつかったオブジェクトのレイヤーを調べBlockであったら、ぶつかった相手のゲームオブジェクトに設定されているRigidbodyを取得し、それにぶつかった面の反対の方向に力を加えます。
transform.forwardでも良さそうな感じがしますが、これだと後ろ向きに当たった時に主人公側に力が加わりおかしくなります。
(後ろ向きで当たったのに、主人公の後ろにまとわりつく感じになります)
ぶつかった面の角度はcol.normalで取得出来ます。
加える力はJoint解除に関係してきますので、適当な数値を設定してください。
また今回のサンプルスクリプトではBlockレイヤーに設定されているゲームオブジェクトに必ずRigidbodyが設定されている事が条件になります。
本来であればRigidbodyが設定されているかどうか調べ、設定されていなければRigidbodyを追加する必要があります。
1 2 3 4 5 | if(col.rigidbody == null) { col.collider.gameObject.AddComponent(Rigidbody); } |
次は銃を撃った時の処理です。
銃を撃った時に当たり判定をしている箇所で相手のRigidbodyに力を加えます。
1 2 3 4 5 6 | if(Physics.Raycast (ray, out hitPoint, myStatus.GetWeaponStatus ().GetWeaponRange (), LayerMask.GetMask("Block"))) { distance = Vector3.Distance(muzzle.position, hitPoint.point); hitPoint.rigidbody.AddForce (muzzle.forward * 500f); } |
銃の場合は銃口(muzzle)が向いている方向に力を加えるようにします。
加えている力は500fを指定していますが、適当に変更してください。
これで処理が完成したのでUnityの実行ボタンを押して確認してみます。
なぜか容量が大きくなったので画質を落としました。
主人公がぶつかると鎖のように振り子運動します。連続して当たるとJointが解除されます。
容量の関係で見れませんが、時間とともに振り子運動が小さくなり止まります。
銃を撃って見ると、Jointが解除されコンポーネントのHingeJointが削除され、ただの1つのゲームオブジェクトになります。
これでJointを使ってオブジェクトを繋げてみる事が出来ました。
Jointが解除されるとコンポーネント自体が削除されます。
これで鎖やドア等を繋げて処理する事が出来るようになります。
Jointを解除したくない場合はBreak ForceとBreak TorqueにInfinityを設定すると解除されないようになります。
Joint機能は撃ち落とせる看板とか木にぶら下がったアイテムを落とすと言った機能を作りたい時に便利かもしれません。

も参考にしてください。