Help us understand the problem. What is going on with this article?

UnityのRigidbodyとColliderで衝突判定

More than 3 years have passed since last update.

動画とスライド

勉強会の記事がブログにあります。(日本法人閉鎖により消滅した模様)
http://www.engineyard.co.jp/blog/2014/shimokita-unity-rigidbody/

サンプルシーン

Step1_unity_-_RigidbodyAndCollision_-_PC__Mac___Linux_Standalone.jpg

https://dl.dropboxusercontent.com/u/6626376/Unity/RigidbodyAndCollision.zip

Rigidbodyでできること

  • 重力、加速度を使った処理
  • 衝突した物体を動かす、衝突された物体の動きに作用する
  • 衝突発生時に任意の処理を実行する

自然落下

Sampleシーンを開く。下記のオブジェクトにAdd ComponentをクリックしてPhysics > Rigidbodyを設定。

Step1_unity_-_RigidbodyAndCollision_-_PC__Mac___Linux_Standalone.jpg

設定項目の意味

項目 意味
Mass 重さ。単位はキログラム
Drag 空気抵抗
Angular Drag 回転に対する空気抵抗
Use Gravity 重力を使う
Is Kinematic 物理演算を無効にする
Interpolate フレーム間の補間
Collision Detection 衝突検知モード。高速で動く物体には変更
Constraits 移動や回転を軸ごとに無効にする

地面が落ちてしまう場合

Rigidbodyは物理演算で動作させるオブジェクトに設定する。壁や床はRigidbodyを付ける必要はない。

地面をすり抜けてしまう場合

Untitled.gif

アセットや変換したモデルがすり抜けてしまう場合はオブジェクトにColliderが設定されていないのが原因。重力で落下した物体が地面に着地するにはそれぞれに下記のコンポーネントが必要になる。
CubeやSphereなどのプリミティブには最初からColliderが付いている。

  • 落下する物体
    • 物体の形に応じたCollider
    • 重力が設定されたRigidbody
  • 受け止める地面
    • 地面の形に応じたCollider

すり抜けて落下していく物体にはPhysics > BoxColliderなどのコンポーネントを設定する。入れ子になっているオブジェクトの場合はそれぞれの子オブジェクトに指定するか、親オブジェクトに指定する。子オブジェクトにColliderを設定した場合は合成した形で親オブジェクトに適用される。

コライダーはシーンでオブジェクトをクリックするとワイヤフレームで表示される。

例

球体にあえて四角形の判定をつけたりすることも出来る。
Step1_unity_-_RigidbodyAndCollision_-_PC__Mac___Linux_Standalone.jpg

レンダラーを無効にすれば表示されないが、判定はあるということも可能。

力を加える

Rigidbodyが設定されたオブジェクトにはスクリプトから力(Force)と回転(Torque)を加えることができる。

メソッド 効果
AddForce 力を加える
AddRelativeForce 相対座標で力を加える
AddTorque 回転を加える
AddRelativeTorque 回転を加える

力を加える時にはForceMode指定することでさらに挙動が変わる。

モード 効果
Force 質量が反映する、連続的な力を加える
Acceleration 質量を考慮しない、連続的な加速を加える
Impulse 質量が反映する、瞬間的な力を加える
VelocityChange 質量を考慮しない、連続的な速度の変化を加える
ControlScript.js
#pragma strict

function Update () {

    var speed = 100;

    if (Input.GetKeyDown(KeyCode.LeftArrow)) {
        rigidbody.AddForce(Vector3.left * speed, ForceMode.Force);
    }

    if (Input.GetKeyDown(KeyCode.RightArrow)) {
        rigidbody.AddForce(Vector3.right * speed, ForceMode.Force);
    }

}

Forcemode.Forceの場合は力を加えて揺らすようなイメージ。

Untitled.gif

Forcemode.VelocityChangeは操作に応じてひとまず動きに反映されるイメージ。

Untitled.gif

ForceModeやspeedを調整してみるとさまざまな動きをする。力を加えると意図しない回転をしてしまうことも多い。プレイヤーなど操作を反映させる場合は不都合な場合も。不都合がな場合はConstraitsで回転を封じる。

上下左右に動く例
#pragma strict

function Update () {

    var speed = 3;

    if (Input.GetKeyDown(KeyCode.LeftArrow)) {
        rigidbody.AddForce(Vector3.left * speed, ForceMode.VelocityChange);
    }

    if (Input.GetKeyDown(KeyCode.RightArrow)) {
        rigidbody.AddForce(Vector3.right * speed, ForceMode.VelocityChange);
    }

    if (Input.GetKeyDown(KeyCode.UpArrow)) {
        rigidbody.AddForce(Vector3.forward * speed, ForceMode.VelocityChange);
    }

    if (Input.GetKeyDown(KeyCode.DownArrow)) {
        rigidbody.AddForce(Vector3.back * speed, ForceMode.VelocityChange);
    }

}

衝突時に処理を行う

衝突が発生すると状況に応じて次のコールバックが実行される。それぞれの処理内で衝突の状況に応じて任意の処理を行うことで動きを作る。この際の処理はRigidbodyがメッセージ機能を使い、相手のオブジェクトと自分のオブジェクトの対応する処理を呼び出している。

コールバック 動作
OnCollisionEnter 他のColliderやRigidbodyオブジェクトに触れた時に呼び出される
OnCollisionExit 他のColliderやRigidbodyオブジェクトに離れた時に呼び出される
OnCollisionStay 他のColliderやRigidbodyオブジェクトに触れ続けている時に呼び出される
衝突時に自分を消去
#pragma strict

function OnCollisionEnter(other:Collision) {

    Destroy(gameObject);

}

Untitled.gif

衝突時に相手を削除
#pragma strict

function OnCollisionEnter(other:Collision) {

    Destroy(other.gameObject);

}

Untitled.gif

衝突対象の判別

衝突対象に無差別に処理を行うのは得策ではないので、衝突対象を判別した上で処理を行う必要がある。そのためにはタグを使った判定を行うのがよい。タグはインスペクタから設定可能。デフォルトのタグの他に、任意のタグを追加可能。

Step3_unity_-_RigidbodyAndCollision_-_PC__Mac___Linux_Standalone_と_Inbox_-_yandod_gmail_com_-_Gmail.jpg

とりあえずプレイヤーと思われるプレゼントにPlayerを設定、衝突されるボールや箱側にスクリプトを付け、 プレイヤーがぶつかってきた時 に処理を行うようにする。

ボールなどに設定するスクリプト
#pragma strict

function OnCollisionEnter(other:Collision) {

    if (other.gameObject.CompareTag('Player')) {
        //move to this object to above.
        gameObject.transform.position = Vector3.up * 5;
    }
}

Untitled.gif

衝突はさせずに処理を行う

ゴールエリアや風が吹くエリア、など一定の範囲にいると処理を行うという場合にはTriggerを使う。具体的にはColliderIsTriggerをOnにすると衝突はしないが専用のコールバックが呼び出される。

Step4_unity_-_RigidbodyAndCollision_-_PC__Mac___Linux_Standalone.jpg

コールバック 動作
OnTriggerEnter 他のColliderやRigidbodyオブジェクトに触れた時に呼び出される
OnTriggerExit 他のColliderやRigidbodyオブジェクトに離れた時に呼び出される
OnTriggerStay 他のColliderやRigidbodyオブジェクトに触れ続けている時に呼び出される
触れてきたオブジェクトを右へ飛ばす
#pragma strict

function OnTriggerEnter(collider:Collider) {
    if (collider.gameObject.CompareTag('Player')) {
        return;
    }
    collider.gameObject.rigidbody.AddForce(
        Vector3.right * 30,
        ForceMode.Impulse
    );

}

Untitled.gif

参考資料

yando
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away