【Unity】RigidbodyのCollision Detection(衝突の検知)を変えて実験
物理的な運動をさせるRigidbodyにおいて、衝突の検知はかなり重要です。
衝突を検知できなければ、物体を透過してしまいますからね。
……と言っておきながら、高速で移動するRigidbodyは結構物体を透過することがあるんです。
そんなときはRigidbodyコンポーネントのCollisionDetection(衝突の検知)の設定を変えて、ちゃんと検知してもらいましょ。
環境
macOS 10.13 High Sierra
Unity2018.1.0f2
4月末にUnity2018が出てたので早速使ってみました。
Rigidbodyについて
Rigidbodyのアタッチ方法や各設定項目の説明は、以下の記事で解説しています。
ざっくり言うと、Unityで物理演算を使うために必要なコンポーネントです。
今回はその中でもCollision Detection(衝突の検知)がテーマ。
Collision Detection(衝突の検知)について
Collision Detectionは日本語訳すると「衝突の検知」。分かりやすくて素敵。
検知方法は『Discrete』、『Continuous』、『ContinuousDynamic』の3通り。
『Discrete』は離散的に衝突を検知します。FixedUpdateが呼ばれたタイミングで衝突を確認するため、そのときにColliderが重なっていないのであれば衝突したと見なされません。
この設定だと高速で移動しているときはオブジェクトを通り抜けることがあります。パフォーマンス的には一番いいのですが、肝心の衝突を検知できないのは困りもの。そんなときは次の設定値を使います。
『Continuous』は、このRigidbodyを持ったオブジェクトの進路上に、Rigidbodyを持っておらず、かつColliderを持つオブジェクトがあれば、FixedUpdateの間であっても連続的に衝突を検知するモード。Continuousはそのまま「連続的に」といった意味。
衝突の対象は壁などのRigidbodyを持たないオブジェクトです。壁にRigidbodyを持たせると吹き飛んだりするので、衝突をさせるためにColliderだけ持たせることが多いです。
進路上に対象のオブジェクトが存在することを確認するため、『Discrete』に比べると重い処理になります。
『ContinuousDynamic』は『Continuous』のケースに加えて、相手がRigidbodyを持っていても、相手のCollision Detectionが『Continuous』または『ContinuousDynamic』であれば連続的に衝突を検知してくれるモード。衝突検知の精度ではこれが一番です。
動いているRigidbodyの軌道まで計算するので、パフォーマンス的には激重さんです。なので高速で動くオブジェクトだけに絞った方がいい感じ。
使用の条件
『Continuous』と『ContinuousDynamic』には条件があって、連続検知してくれるコライダーが決まっています。
スクリプトリファレンスを見ると、Sphere Collider、Capsule Collider、Box Colliderを使っているときに連続検知をしてくれます。Unityが事前に形を知っているコライダーで計算してくれるみたい。
ユーザー側で形を決められるMesh ColliderやTerrain Colliderでは連続検知をしてくれないので注意。
3Dモデルが複雑な形をしているのであれば、複合コライダーとしてSphere Collider、Capsule Collider、Box Colliderを組み合わせて使ってみるのも一つの手だと思います。
複合コライダーについては、マニュアルのRigidbodyの項目をご覧あれ。
オブジェクトのすり抜け
オブジェクトのすり抜けについては、テラシュールブログさんの以下の記事がとても参考になります。
ここでは、衝突する側とされる側でそれぞれのCollision Detectionを変え、衝突がどうなるか見てみましょ。
衝突する側として、以下の3つのボールを用意します。
- Collision Detection : Discrete
- Collision Detection : Continuous
- Collision Detection : ContinuousDynamic
Collision Detectionの設定のみ変え、他の値はRigidbodyのデフォルトのままとします。
これらのボールに、同時に力を与えた時の運動を観察。ForceModeはImpulseとし、加えた力の大きさは画面左上に表示しています。FixedUpdate()のスキをついて欲しいので、強めの力で飛び出してもらいましょ。
まずは加える力を小さめにして、ゆっくりと衝突させてみます。衝突相手のピンクのオブジェクトはRigidbodyを持っておらず、Box Colliderのみを持った壁です。
この壁を衝突相手として、加える力を大きくしてみます。『Discrete』に設定したボールはすり抜けてしまいました。一方で、『Continuous』と『ContinuousDynamic』は、飛び出す速度は同じにも関わらず、ちゃんと衝突できていますね。
続いて、衝突相手がRigidbodyを持っている場合。緑色のオブジェクトはRigidbodyを持っており、動かないようにmassとdragを300にしています。このオブジェクトでは、Collision Detectionの値を『Discrete』にしています。
『Discrete』と『Continuous』はすり抜け、『ContinuousDynamic』だけきちんと衝突しています。
マニュアルにある通り、相手がRigidbodyを持っているかどうかで選択すべき設定が異なるのがわかります。
動く物体とぶつけてみる
上では壁相手の衝突だったので、今度は動いていて、かつ衝突相手もCollision Detectionの値を変えてみましょうか。
画面左のオブジェクトと画面右のオブジェクトに、同じ大きさで向きが逆の力を加えます。相対速度が倍なので超高速で駆け抜けます。
まずは衝突相手(ピンクのボール)が『Discrete』の場合です。一瞬のことで見分けにくいですが、ピンクのボールが画面左まで突き抜けているので、衝突が起こらなかったようです。
画面左にいる『ContinuousDynamic』のボールもすり抜けていますね。壁のように動かないオブジェクトとの衝突は検知してくれましたが、高速で動くオブジェクトだと無理なようです。
続いてピンクのボールが『Continuous』になっている場合です。一方が『ContinuousDynamic』であれば、『Continuous』相手の衝突を検知してくれました。
両方のオブジェクトで衝突を検知できているみたい。
最後にピンクのボールが『ContinuousDynamic』になっている場合です。『ContinuousDynamic』同士はもちろんのこと、上のケースと同じように『Continuous』とも衝突。
4つ分のデバッグ文が出力されているので、バッチリ検知されています。
実験結果のマトリクス
実験した結果を表にすると以下のようになります。
Collision Detection | Rigidbodyなし | Rigidbodyあり | ||
Discrete | Continuous | ContinuousDynamic | ||
Discrete | × | × | × | △ |
Continuous | ○ | × | × | ○ |
ContinuousDynamic | ○ | △ | ○ | ○ |
○が連続的な衝突の検知が可能、×は連続的な検知ができない組み合わせです。
△にしているところは、Discrete側が止まっている場合に検知できることがあります。
……場合によっては検知してくれる、なんてのを過信するのは禁物なので、高速で動くオブジェクトにはちゃんと『ContinuousDynamic』を設定しておいた方がいいですね。
まとめ
Rigidbodyをアタッチしたオブジェクトがすり抜けるのを防ぐCollisionDetection。
連続的に衝突を検知してくれる優れものなので、条件に気を付けつつ、高速に移動する物体の衝突をガンガン検知しましょ。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】RigidbodyのInterpolate(補間)を変えて実験 2018.05.16
-
次の記事
【Unity】RigidbodyのConstraints(制限)を変えて実験 2018.05.17
[…] 【Unity】RigidbodyのCollision Detection(衝突の検知)を変えて実験 […]