- 主にゴルフゲームを作る際にボールを飛ばして静止するまで次の行動をさせたくない
- この「静止している状態」をどのように取得するか
Rigidbody.IsSleeping
- https://docs.unity3d.com/ja/current/ScriptReference/Rigidbody.IsSleeping.html
- https://docs.unity3d.com/ja/current/Manual/RigidbodiesOverview.html (Sleepingの欄参照)
-
Rigidbody.IsSleeping()
でrigidbodyが静止状態か否か取る事が出来る
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
に代入する
動摩擦力(PhysicMaterial.DynamicFriction)を設定する
- https://docs.unity3d.com/ja/current/Manual/class-PhysicMaterial.html
- Colliderに対して、PhysicMaterialを設定する事が出来る
- PhysicMaterialは、特定のオブジェクトの摩擦や跳ね返り効果の設定
- **[Project]=>[create]=>[PhysicMaterial]**で生成可能
-
DynamicFriction
は動摩擦力を表す- この値が大きい程、物体(床含む)と衝突している限り、基本的には早く静止する
-
FrictionCombine
(2物体間の摩擦の処理方法) の設定により、衝突相手の摩擦力が低い場合には摩擦が大きくならないケースがある
- 余談: Physics マネージャーからdefaultのPhysicMaterialを設定することも可能
抗力(Rigidbody.drag)を設定する
- https://docs.unity3d.com/ja/current/ScriptReference/Rigidbody-drag.html
-
Rigidbody.drag
をInspector上、もしくはScipt上で変更する - 抗力を大きめに設定する事で速度が減衰する
ゲームの処理時間を早くする
- 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倍速)
-
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)
- https://docs.unity3d.com/ja/current/Manual/class-PhysicsManager.html
- https://docs.unity3d.com/ja/current/ScriptReference/Rigidbody-sleepThreshold.html
-
SleepThreshold
の値が静止状態を判定する為の閾値となる -
SleepThreshold
は「質量で正規化された運動エネルギーのしきい値」を指す - 運動エネルギーEは
K = (1/2)mv^2
で求めることが出来る- m = mass (質量)
- v = velocity (速度)
- 今回は「質量で正規化された運動エネルギー」なので質量は考慮しない
- 今回検証に使用したコードは以下
- 「質量で正規化された運動エネルギー」の取得はコチラを拝借
- (余談: magnitude ^ 2 より sqrMagnitude のほうが高速)
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側の実装で)何が正しい式なのか知ってる方いたら教えてください///