1. はじめに
こんにちは、azarashin です。 最近のゲームには主人公のキャラクターが接触すると障害物が動いたり倒れたりするようなケースをよく見るかと思います。 このような表現には物理演算処理が用いられています。 昔は物理演算処理をそれぞれの開発者が実現する必要があり、特に個人で開発している人にとっては手間のかかる部分だったのですが、 Unity にはこの物理演算処理を簡単に使う機能が備わっています。 本記事ではこの物理演算処理を行うためのRigidBody について紹介していきたいと思います。
2. 自由落下
今回は平面の板の上に球体を落下させ、板の上を球体が転がるようなケースを再現してみます。 Hierarchy 上にCube(立方体)とShpere(球)を生成し、形を整えます。
今回は球の下に立方体を設置し、立方体を平べったく引き伸ばすようにCube のPosition とScale を調整し、床とします。
このままではまだ物理シミュレーションができませんので、Cube オブジェクトを選択した状態でInspector のAdd Component をクリックし、Cube オブジェクトにRigidbody コンポーネントを付与します。
同様に、Sphere オブジェクトにもRigidbody コンポーネントを付与します。
これでエディタを再生してみます。
なんと、床とボールが両方落下してしまいました…。ボールはともかく床は落下して欲しくなかったのですが…。 Unity のRigidbody を付与すると、初期状態では重力が有効になっており、エディタを再生すると落下してしまいます。 今回は床に対して重力の影響をなくしてしまいたいので、床(Cubeオブジェクト)のRigidbody コンポーネントのUse Gravity からチェックを外します。 これで床に対して重力の影響はなくなります。
これで再度トライしてみましょう。
…そうじゃない感が漂っています…。 重力の影響がなくなるということは宇宙空間に浮かんでいるようなものなのですが、だからと言って動かなくなるというわけではありません。 重力という推進力を持った球がぶつかってきたら、床は球に押されて動いてしまいます。 今回の床のように絶対に動かしたくないオブジェクトに対しては重力の影響をなくすだけでなく、位置と姿勢を固定させる必要があります。 そのためには、Rigidbody コンポーネントのCoonstraints 以下にあるFreeze Position とFreeze Rotation のX, Y, Z 成分すべてにチェックを入れます。
これで床の位置と姿勢が固定され、ボールが衝突しても床が動かなくなり、ボールが床の上を転がって落ちていくようになります。
3. 力を加える
今度は重力以外の力をオブジェクトに加えてみます。 この例では重力の影響をなくし、無重力空間でオブジェクトに力を加えるものとします。
力をオブジェクトに加えるためにはスクリプトを記述する必要があります。 今回はSampleRigidBody.cs というスクリプトファイルを作成し、Sphere オブジェクトに付与します。
SampleRigidBody.cs の中身は以下のように記述します。
using UnityEngine; [RequireComponent(typeof(Rigidbody))] public class SampleRigidBody : MonoBehaviour { [SerializeField] Vector3 _force; [SerializeField] ForceMode _forceMode; private Rigidbody _body; // Start is called before the first frame update void Start() { _body = GetComponent<Rigidbody>(); _body.AddForce(_force, _forceMode); } }
力を加えるときはRigidbody コンポーネントのAddForce メソッドを用います。第一引数には加える力の向きと方向を示すベクトル(Vector3型)を渡します。 このスクリプトでは、エディタから_force のベクトルを設定することで加える力を設定できるようにしています。 第二引数には力の加え方を示すForceMode という列挙子を与えます。 ForceMode については公式ドキュメントにも説明がありますので、必要に応じて参照してください。
ForceMode は以下のような値をとりますので必要に応じて使い分けてください。
ForceMode | 質量を無視するかどうか | 力を加えるタイミング |
---|---|---|
Force | 使用する | 継続的に加える |
Acceleration | 無視する | 継続的に加える |
Impulse | 使用する | 一瞬だけ加える |
VelocityChange | 無視する | 一瞬だけ加える |
さて、さっそく力を加えてみます。 まず、重さ(Mass)を1にして、力2 をx軸方向正の向きに加えてみます。 今回の例ではForceMode をすべてImpulse にしておきます。つまり、力を加えるタイミングは一瞬で、オブジェクトに設定された質量によって移動速度が変化するようになります。
球がx軸正の方向に転がっていきました。
今度は重さ(Mass)を0.25にして、力-2 をx軸方向正の向きに加えてみます。 これは言い換えると力2 をx軸方向負の向きに加えることを意味します。
再び動作確認をしてみましょう。
力を加える向きが反対方向になりましたので、球が転がっていく方向も反対方向へ変化しました。 また、先ほどのケースと比べて球の転がる速度がかなり速くなっています。
これは高校物理で学んだニュートンの運動方程式を参考にするとよいでしょう。
運動方程式によると
加えた力(F) = 質量(m) x 加速度(a)
つまり
加速度(a) = 加えた力(F) / 質量(m)
となります。 今回はオブジェクトの重さが1から0.25へと変化しました。即ち重さが1/4倍になりましたので、(瞬間的に加わる)加速度は4倍になり、静止状態から動き始めた時の速度も4倍になります。
最後に、先ほどのオブジェクト2種類を互いにぶつけてみましょう。
ぶつかると両者はきれいに静止しました。 直感的には正面衝突すると互いに反発しそうな感じがするのですが、動作確認をすると両者は停止しました。 これは反発係数の初期値が0であることが原因です。 両者の重さがそれぞれ異なりますので同じ力を加えると移動速度は異なるのですが、 加えられた力が同じですのでどちらも同じ運動エネルギーを持ちます。一方、無重力なので位置エネルギーは共に0です。 詳細は省略しますが、同じ運動エネルギーで反発係数0で正面衝突するとこのように両者その場で静止します。
反発係数を変更するにはProject 欄で右クリック→Create→Physics Material を選択します。
作成されたPhysics Material を選択し、Inspector を見てみると各種パラメータを確認することができます。
反発係数(Bunciness)の初期値が0 になっているので、これを0.2 に変更してみましょう。
そして、2つのSphere オブジェクトそれぞれに付与されているSphere Collider のMaterial 欄に作成したPhysics Material をドラッグ&ドロップします。
以上のように反発係数を変更して再度衝突させてみましょう。
今度は衝突後に静止せず、反発するようになりました。
4. 終わりに
Rigidbody を使用するとオブジェクト同士の衝突を再現する物理演算を行うことができます。 本記事の最後で反発係数について触れましたが、これ以外にも静止した状態での摩擦係数や動いている状態での摩擦係数、空気抵抗といったいくつかのパラメータを設定し、より複雑な物理演算を行うことができます。
物理演算を行う際に注意することもあります。例えば計算量です。物理演算の対象となるオブジェクトが増えるとその分計算量も増え、描画品質に影響がでてきます。 また、特に操作するキャラクター自体に物理演算を施すと思ったように動かなくなることもあります。 そのため、
- 本当にその物理演算が必要なのか?
- それともより簡易的な計算で代替する方がよいのではないか?
- 物理演算の対象を絞り込む必要があるのではないか?
といったことをバランスを考慮しながら決めていく必要がそのうちでてきます。
最初は本記事で紹介したような簡単な例で動作確認を行い、徐々に複雑なケースにトライしてみると良いかと思います。