【Unity】RigidBodyについて

06/12/2018

RigidBodyについて

GameObjectを物理特性エンジンを使って制御できます。使用したいObjectにアタッチすることで使用できます。

RigidBodyは、リアルサイズで考えるよりも、キャラクタサイズを人間に置き換えて換算したほうが上手に使えるらしいです。例えばガンダムが18メートルだったとしても、1/10スケールして、1.8mで設定するのがいいかと思います。ガンダムが時速60kmで走るとしたら、時速6kmです。(ちょっと遅いねww)
いろいろと単位が大きい・小さいとあたり判定が突き抜けたり、都合が悪いです。


Mass オブジェクトの質量 (単位 : kg)です。スケールを合わせてなんとなく設定することになります。衝突したときの挙動に影響します。
Drag 移動する際の推進力を減衰させます。摩擦力みたいもの。小さすぎると氷の上のように滑ります。0~999,infinityとすると動かなくなります。
Angular Drag 回転する際に回転力を減衰させます。0~999,infinity
Use Gravity 重力の影響を受けます。標準の重力は9.81 PhysicsManagerのGravityで変更できます。
空気抵抗をある程度大きくした場合、落下速度が遅くなるので重力で調整します。
また、軸を変更すれば壁方向に重力を発生させられます。

<例>


	void Start () {
		Physics.gravity = new Vector3(0, -9.81f, 0); 	//地面方向に
		Physics.gravity = new Vector3(0, 9.81f, 0); 	//空に向かって
	}

Is Kinematic Trueで物理特性エンジンが無効になります。
Interpolate Rigidbodyの動きがぎこちないときに試すらしいです。
None     補間を適用しない。
Interpolate 前フレームの Transform にもとづいて Transform のスムージング。
Extrapolate 前フレームの Transform にもとづいて Transform のスムージング。
Collision Detection Constraints リジッドボディの動きに関する制限します。
Freeze Position ワールド座標系の XYZ 軸で移動を制限します。
Freeze Rotation ワールド座標系の XYZ 軸で回転を制限します。(TPSの場合は、X軸 Z軸を制限するのが一般的)


移動方法

次に動かし方です。3つの方法があります。

①MovePositionを使った場合
移動座標を直接指定します。transform.positionと同じように使えます。下記のようにJumpに使うとプルプルするかもしれません。


    public Vector3 JumpSpeed = new Vector3(0, 10, 0); //ジャンプのスピード
    void FixedUpdate()
    {
        if (Input.GetButton("Jump")
        {
            Debug.Log("DEBUG:Jump ON");
            RigidbodyComponent.MovePosition(RigidbodyComponent.position + jumpSpeed * Time.deltaTime);
     }
   }

スピード(Vector3(0, 10, 0))×差分 を現在の位置に足して移動します。UNITYは時間管理が重要です。Time.deltaTimeについては、前回描写からの経過時間になります。

②AddForce()系を使った移動
オブジェクトに力を加えます。物を押すことで移動していくイメージです。
軸に対して移動と回転があります。グローバル座標の軸に対して力を加えるものと、ローカル座標軸に対して追加する2種類があります。


AddForce      グローバル座標の軸に対してrigidbodyに力を追加します。
AddTorque      グローバル座標の軸に対してrigidbodyにトルクを追加します。
AddRelativeFor​​ce ローカル座標にの軸にrigidbody相対に力を追加します。
AddRelativeTorque ローカル座標にの軸にrigidbody相対にトルクを追加します。

さらに特殊な力の加え方が2種類(使ったことがありません)
AddForceAtPosition 位置に力を加える。オブジェクト上のトルクと力を加えます。
AddExplosionForce 爆発の影響をシミュレートしrigidbodyに力を加える。

力の与え方に種類があります。
Force      MASS(物体重量)を考慮してrigidbodyに力を加えます。
Acceleration  MASS(物体重量)を考慮せずにrigidbodyに力を加えます。
Impulse     MASS(物体重量)を考慮してrigidbodyに瞬間的な力を加えます。
VelocityChange MASS(物体重量)を考慮せずにrigidbodyに瞬間的な力を加えます。
必要に応じて使い分ける必要があります。

ちなみに、トルクはねじれる力です。

自分の感覚ですが、
TPSやFPSの場合は、AddRelativeForce()を利用します。ローカル座標のためキャラクタの向かっている方向に対して力を与えることができます。
AddForce()はグローバル軸に対して力が加わりますので、キャラクタの向きに影響されずに、常に一定の方向に移動・回転すると考えてください。
VelocityChange等の選定基準は、MASS(物体重量)の考慮となります。考慮すると動きだしが重量によっては鈍くなります。アクションGAMEの場合は、重量を無視するのがよいと思います。シュミレーション系(ドライブ系や飛行機もの?)は、MASSを使うとそれらしくなると思います。



    public float JumpSpeed = 100; //ジャンプのスピード

    void FixedUpdate()
    {
        if (Input.GetButton("Jump"))
        {
            //up(上方向)に
            RigidbodyComponent.AddForce(Vector3.up * jumpSpeed * Time.deltaTime , ForceMode.VelocityChange);
     }
    }

SAMPLEプログラムです。参考にしてね。


// Type1_CharacterController
// Create 20150308 アレをイメージしたコントローラ
// WASD + JUMP SHIFTでローラダッシュ
//
// Update  2015.3.11 Jumpwo実装

using UnityEngine;
using System.Collections;

public class Type1_CharacterController : MonoBehaviour
{
    public float Gravity = 9.81f;       //重力
    public float ForwardSpeed = 5;      //前進のスピード 
    public float BackwardSpeed = 2;     //交信のスピード 
    public float RotationSpeed = 10;    //旋回の速度 
    public float StrafeSpeed = 5;       //横にスライド 
    public float JumpSpeed = 100; //ジャンプのスピード
    public float JumpTime = 4;
    private float JumpEnergy = 0;
    public float JumpEnergyFull = 0.5f; 
    public float JumpBetweenInterval = 1.0f; 


    public Animator AnimatorComponent;
    public Rigidbody RigidbodyComponent;

    void Start()
    {
        AnimatorComponent = GetComponent();       //AnimatorComponentの保持
        RigidbodyComponent = GetComponent();     //RigidbodyComponentの保持
        Physics.gravity = new Vector3(0, Gravity, 0);       //重力の設定
    }
    void Update()
    {
        //未実装
    }
    void FixedUpdate()
    {
        if (Input.GetButton("Jump") && AnimatorComponent.GetBool("Jump") == false)
        {
            Debug.Log("DEBUG:Jump 初回");
            AnimatorComponent.SetBool("Jump", true);
            JumpEnergy = JumpEnergyFull;
        }
        else if (Input.GetButton("Jump") && JumpEnergy > 0 && AnimatorComponent.GetBool("Jump") == true)
        {
            Debug.Log("DEBUG:Jump ON");
            RigidbodyComponent.AddRelativeForce(Vector3.up * JumpSpeed * Time.deltaTime, ForceMode.VelocityChange);
            JumpEnergy = JumpEnergy - Time.deltaTime;
        }        
        else if (AnimatorComponent.GetBool("Jump") == true && JumpEnergy > 0)
        {
            Debug.Log("DEBUG:Jump OFF");
        }
        else
        {
            Debug.Log("DEBUG:自由落下");
        }

        if (Input.GetAxis("Vertical") > 0.1 || Input.GetAxis("Vertical") < -0.1) { if (Input.GetAxis("Vertical") > 0.1)
            {
                RigidbodyComponent.AddTorque(new Vector3(0, RotationSpeed * Input.GetAxis("Horizontal") * Time.deltaTime, 0), ForceMode.VelocityChange);
                RigidbodyComponent.AddRelativeForce(Vector3.forward * ForwardSpeed * Input.GetAxis("Vertical") * Time.deltaTime, ForceMode.VelocityChange);

                AnimatorComponent.SetFloat("Speed", (Input.GetAxis("Vertical") * ForwardSpeed * Time.deltaTime));
                AnimatorComponent.SetFloat("Strafe", 0);
            }
            else
            {
                RigidbodyComponent.AddTorque(new Vector3(0, RotationSpeed * Input.GetAxis("Horizontal") * Time.deltaTime, 0), ForceMode.VelocityChange);
                RigidbodyComponent.AddRelativeForce(Vector3.forward * BackwardSpeed * Input.GetAxis("Vertical") * Time.deltaTime, ForceMode.VelocityChange);

                AnimatorComponent.SetFloat("Speed", (Input.GetAxis("Vertical") * BackwardSpeed * Time.deltaTime));
                AnimatorComponent.SetFloat("Strafe", 0);
            }
        }
        else
        {
            if (Input.GetAxis("Horizontal") > 0.1)
            {
                RigidbodyComponent.AddRelativeForce(Vector3.right * StrafeSpeed * Input.GetAxis("Horizontal") * Time.deltaTime, ForceMode.VelocityChange);
            }
            else
            {
                RigidbodyComponent.AddRelativeForce(Vector3.right * StrafeSpeed * Input.GetAxis("Horizontal") * Time.deltaTime, ForceMode.VelocityChange);
            }
            AnimatorComponent.SetFloat("Speed", 0);
            AnimatorComponent.SetFloat("Strafe", (Input.GetAxis("Horizontal") * StrafeSpeed) * Time.deltaTime);
        }
    }
    void OnCollisionExit(Collision col)
    {
        if (col.gameObject.CompareTag("Ground"))
        {
            AnimatorComponent.SetBool("IsGrounded", false);
            Debug.Log("Debug:IsGrounded  false");
        }
    }
    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject.CompareTag("Ground"))
        {
            AnimatorComponent.SetBool("IsGrounded", true);
            AnimatorComponent.SetBool("Jump", false);
            Debug.Log("DEBUG:IsGrounded true");
        }
    }
}

スポンサーリンク