LoginSignup
26
25

More than 5 years have passed since last update.

[Unity] Rigidbodyで静止判定を取る/素早く静止させる

Last updated at Posted at 2016-09-21
  • 主にゴルフゲームを作る際にボールを飛ばして静止するまで次の行動をさせたくない
  • この「静止している状態」をどのように取得するか

Rigidbody.IsSleeping

issleep.gif

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class SleepTestText : MonoBehaviour
{
    public Rigidbody rb;
    public Text isSleepText;

    void FixedUpdate()
    {
        isSleepText.text = rb.IsSleeping() ? "Sleep" : "Active";
    }  
}

素早く静止させる手段

SleepThresholdを大きめに設定する

  • SleepThresholdの値は以下のように変更する事が出来る
    • Physics マネージャー [Edit]=>[ProjectSettings]=>[Physics] 内で変更する (全てのRigidbodyに対するdefault値の設定)
    • Script内でRigidbody.sleepThreshold に代入する

sleepthreshold.png

動摩擦力(PhysicMaterial.DynamicFriction)を設定する

  • https://docs.unity3d.com/ja/current/Manual/class-PhysicMaterial.html
  • Colliderに対して、PhysicMaterialを設定する事が出来る
    • PhysicMaterialは、特定のオブジェクトの摩擦や跳ね返り効果の設定
    • [Project]=>[create]=>[PhysicMaterial]で生成可能
  • DynamicFriction は動摩擦力を表す
    • この値が大きい程、物体(床含む)と衝突している限り、基本的には早く静止する
    • FrictionCombine(2物体間の摩擦の処理方法) の設定により、衝突相手の摩擦力が低い場合には摩擦が大きくならないケースがある
  • 余談: Physics マネージャーからdefaultのPhysicMaterialを設定することも可能

material.gif

friction.gif

抗力(Rigidbody.drag)を設定する

drag.png

drag.gif

ゲームの処理時間を早くする

  • https://docs.unity3d.com/ja/current/ScriptReference/Time-timeScale.html
  • 裏道的なアプローチではあるが、早送りがあるとユーザにストレスを感じさせない
  • Time.timeScale を変更する事でゲーム内の時間の速度を早めたりお染めたり出来る
    • Time.timeScale = 1.0f がデフォルトの状態
    • Time.timeScale = 2.0f で早送り (2倍速)
    • Time.timeScale = 0.5f でスローモーション (0.5倍速)

timescale.gif

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections;

public class TimeScaleButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    // 3倍速
    public float rate = 3.0f;
    public Image image;

    public void OnPointerDown(PointerEventData eventData)
    {
        Time.timeScale = rate;
        image.enabled = true;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        Time.timeScale = 1.0f;
        image.enabled = false;
    }
}

(要検証) 静止状態になる条件 (SleepThreshold)

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class SleepTestText : MonoBehaviour
{
    public Rigidbody rb;
    public Text kineticEnergyText;
    public Text sleepThresholdText;
    public Text isSleepText;

    void FixedUpdate()
    {
        float e = GetMassNormalizedKineticEnergy(rb);

        kineticEnergyText.text  = "kineticEnergy: " + e.ToString();
        sleepThresholdText.text = "sleepThreshold: " + rb.sleepThreshold.ToString();
        isSleepText.text        = rb.IsSleeping() ? "Sleep" : "Active";
    }

    public static float GetMassNormalizedKineticEnergy(Rigidbody r)
    {
         // Linear energy
         float E = 0.5f * r.mass * Mathf.Pow(r.velocity.magnitude, 2f);

         // Angular energy
         E += 0.5f * r.inertiaTensor.x * Mathf.Pow(r.angularVelocity.x, 2f);
         E += 0.5f * r.inertiaTensor.y * Mathf.Pow(r.angularVelocity.y, 2f);
         E += 0.5f * r.inertiaTensor.z * Mathf.Pow(r.angularVelocity.z, 2f);

         // Mass-normalized
         return E /= r.mass;
     }    
}
  • しかし (上記のフォーラムでも触れられているが) e < sleepThreshold を満たしてもSleepにならない...
    • (Unity側の実装で)何が正しい式なのか知ってる方いたら教えてください///

threshold.gif

26
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
25