0からスタート!ゲーム開発ブログ

ゲーム開発に関する様々な記事を更新します

Unityの物理演算コンポーネント「Rigidbody 」の使い方

1. はじめに

こんにちは、azarashin です。 最近のゲームには主人公のキャラクターが接触すると障害物が動いたり倒れたりするようなケースをよく見るかと思います。 このような表現には物理演算処理が用いられています。 昔は物理演算処理をそれぞれの開発者が実現する必要があり、特に個人で開発している人にとっては手間のかかる部分だったのですが、 Unity にはこの物理演算処理を簡単に使う機能が備わっています。 本記事ではこの物理演算処理を行うためのRigidBody について紹介していきたいと思います。

2. 自由落下

今回は平面の板の上に球体を落下させ、板の上を球体が転がるようなケースを再現してみます。 Hierarchy 上にCube(立方体)とShpere(球)を生成し、形を整えます。

Cube(立方体)とSphere(球)を生成する

今回は球の下に立方体を設置し、立方体を平べったく引き伸ばすようにCube のPosition とScale を調整し、床とします。

立方体を傾けて引き伸ばす

このままではまだ物理シミュレーションができませんので、Cube オブジェクトを選択した状態でInspector のAdd Component をクリックし、Cube オブジェクトにRigidbody コンポーネントを付与します。

RigidBody コンポーネントを割り当てる(立方体)

同様に、Sphere オブジェクトにもRigidbody コンポーネントを付与します。

RigidBody コンポーネントを割り当てる(球)

これでエディタを再生してみます。

床と球が両方落下してしまう

なんと、床とボールが両方落下してしまいました…。ボールはともかく床は落下して欲しくなかったのですが…。 Unity のRigidbody を付与すると、初期状態では重力が有効になっており、エディタを再生すると落下してしまいます。 今回は床に対して重力の影響をなくしてしまいたいので、床(Cubeオブジェクト)のRigidbody コンポーネントのUse Gravity からチェックを外します。 これで床に対して重力の影響はなくなります。

立方体の重力を無効にする(チェックを外す)

これで再度トライしてみましょう。

床に球が衝突(そして一緒に落ちる…)

…そうじゃない感が漂っています…。 重力の影響がなくなるということは宇宙空間に浮かんでいるようなものなのですが、だからと言って動かなくなるというわけではありません。 重力という推進力を持った球がぶつかってきたら、床は球に押されて動いてしまいます。 今回の床のように絶対に動かしたくないオブジェクトに対しては重力の影響をなくすだけでなく、位置と姿勢を固定させる必要があります。 そのためには、Rigidbody コンポーネントのCoonstraints 以下にあるFreeze Position とFreeze Rotation のX, Y, Z 成分すべてにチェックを入れます。

床の位置・姿勢を固定する

これで床の位置と姿勢が固定され、ボールが衝突しても床が動かなくなり、ボールが床の上を転がって落ちていくようになります。

球が床から転がり落ちる

3. 力を加える

今度は重力以外の力をオブジェクトに加えてみます。 この例では重力の影響をなくし、無重力空間でオブジェクトに力を加えるものとします。

力をオブジェクトに加えるためにはスクリプトを記述する必要があります。 今回はSampleRigidBody.cs というスクリプトファイルを作成し、Sphere オブジェクトに付与します。

スクリプトを作成してアタッチする(SampleRigidBody)

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 については公式ドキュメントにも説明がありますので、必要に応じて参照してください。

docs.unity3d.com

ForceMode は以下のような値をとりますので必要に応じて使い分けてください。

ForceMode 質量を無視するかどうか 力を加えるタイミング
Force 使用する 継続的に加える
Acceleration 無視する 継続的に加える
Impulse 使用する 一瞬だけ加える
VelocityChange 無視する 一瞬だけ加える

さて、さっそく力を加えてみます。 まず、重さ(Mass)を1にして、力2 をx軸方向正の向きに加えてみます。 今回の例ではForceMode をすべてImpulse にしておきます。つまり、力を加えるタイミングは一瞬で、オブジェクトに設定された質量によって移動速度が変化するようになります。

重さ1に対して力2を一瞬加える

球がx軸正の方向に転がっていきました。

重さ1に対して力2を一瞬加える(デモ)

今度は重さ(Mass)を0.25にして、力-2 をx軸方向正の向きに加えてみます。 これは言い換えると力2 をx軸方向負の向きに加えることを意味します。

重さ0.25に対して力-2を一瞬加える

再び動作確認をしてみましょう。

重さ0.25に対して力-2を一瞬加える(デモ)

力を加える向きが反対方向になりましたので、球が転がっていく方向も反対方向へ変化しました。 また、先ほどのケースと比べて球の転がる速度がかなり速くなっています。

これは高校物理で学んだニュートン運動方程式を参考にするとよいでしょう。

ja.wikipedia.org

運動方程式によると

加えた力(F) = 質量(m) x 加速度(a)

つまり

加速度(a) = 加えた力(F) /  質量(m)

となります。 今回はオブジェクトの重さが1から0.25へと変化しました。即ち重さが1/4倍になりましたので、(瞬間的に加わる)加速度は4倍になり、静止状態から動き始めた時の速度も4倍になります。

最後に、先ほどのオブジェクト2種類を互いにぶつけてみましょう。

反対向きに同じ力を加えると衝突時に静止する

ぶつかると両者はきれいに静止しました。 直感的には正面衝突すると互いに反発しそうな感じがするのですが、動作確認をすると両者は停止しました。 これは反発係数の初期値が0であることが原因です。 両者の重さがそれぞれ異なりますので同じ力を加えると移動速度は異なるのですが、 加えられた力が同じですのでどちらも同じ運動エネルギーを持ちます。一方、無重力なので位置エネルギーは共に0です。 詳細は省略しますが、同じ運動エネルギーで反発係数0で正面衝突するとこのように両者その場で静止します。

反発係数を変更するにはProject 欄で右クリック→Create→Physics Material を選択します。

Physics Material の作成

作成されたPhysics Material

作成されたPhysics Material を選択し、Inspector を見てみると各種パラメータを確認することができます。

Bunciness(反発係数)の初期値は0

反発係数(Bunciness)の初期値が0 になっているので、これを0.2 に変更してみましょう。

Bunciness(反発係数)を0.2に変更

そして、2つのSphere オブジェクトそれぞれに付与されているSphere Collider のMaterial 欄に作成したPhysics Material をドラッグ&ドロップします。

Physics Material をShpere Collider に割り当て

以上のように反発係数を変更して再度衝突させてみましょう。

反発係数を変更して再度衝突させる

今度は衝突後に静止せず、反発するようになりました。

4. 終わりに

Rigidbody を使用するとオブジェクト同士の衝突を再現する物理演算を行うことができます。 本記事の最後で反発係数について触れましたが、これ以外にも静止した状態での摩擦係数や動いている状態での摩擦係数、空気抵抗といったいくつかのパラメータを設定し、より複雑な物理演算を行うことができます。

物理演算を行う際に注意することもあります。例えば計算量です。物理演算の対象となるオブジェクトが増えるとその分計算量も増え、描画品質に影響がでてきます。 また、特に操作するキャラクター自体に物理演算を施すと思ったように動かなくなることもあります。 そのため、

  • 本当にその物理演算が必要なのか?
  • それともより簡易的な計算で代替する方がよいのではないか?
  • 物理演算の対象を絞り込む必要があるのではないか?

といったことをバランスを考慮しながら決めていく必要がそのうちでてきます。

最初は本記事で紹介したような簡単な例で動作確認を行い、徐々に複雑なケースにトライしてみると良いかと思います。