物理演算のためのFixedUpdate
CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 4/63。
Unityは、フレームレートにかかわらず、0.02秒間隔の固定物理ステップ(Time.fixedDeltaTime)で、1秒あたり50回、剛体を動かします。FixedUpdate()は各ステップの直前に実行されます。Update()は描画されたフレームごとに1回実行され、1秒あたり30回、60回、または144回実行されることがあります。144回の場合、ほとんどのフレームでは物理ステップがまったく発生せず、低速なコンピューターでは1つのフレーム内に2回発生することもあります。
ここから2つのルールが導かれます。Update()で力を加えるとフレームごとに1回加わるため、コンピューターが速いほど強く押されます。時間をかけて作用する力はFixedUpdate()に記述します。また、GetKeyDownがtrueになるのは1フレームだけです。そのフレームに物理ステップがなければ、FixedUpdate()はそれを認識できず、キー入力は失われます。そのため、入力はUpdate()で読み取り、boolに記録して、FixedUpdate()で処理します。このボートは一定の風に押され、クリックすると横方向にダッシュします。
private bool dashQueued;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
dashQueued = true; // クリックを記憶する
}
}
void FixedUpdate()
{
rb.AddForce(Vector3.forward * wind); // 毎ステップ、一定の力を加える
if (dashQueued)
{
rb.AddForce(Vector3.right * 4f, ForceMode.Impulse);
dashQueued = false; // 1クリックにつき1回ダッシュ
}
}使ったあとにboolをクリアすることが重要です。trueのままにすると、毎ステップダッシュしてしまいます。カエルのジャンプのように、単一のインパルスをUpdate()から直接加えることもできます。boolを使えば、すべての押す力を、それが作用する力のそばにまとめて記述できます。押し続けるキー(GetKey、GetAxis)は瞬間ではなく状態を表すため、FixedUpdate()から直接読み取れます。FixedUpdate()内では、Time.deltaTimeはステップの時間である0.02を返します。
チャレンジ
簡単凍った湖のそりは、2つの処理がどちらも間違ったメソッドにあります。矢印キーによる推進処理がUpdate()内にあるため、コンピューターの速度が速いほど強く押されます。スペースキーによるインパルスでのジャンプ処理がFixedUpdate()内にあるため、キーを押しても反応しないことがあります。
- 矢印キーによる推進処理を
FixedUpdate()に移します。 Update()でスペースキーの入力を読み取り、hopPressedという名前のboolに保存します。FixedUpdate()では、それがセットされているときにジャンプし、その後クリアします。
Playを押して両方を試し、次にCheckを押します。
自分で試してみよう
using UnityEngine;
public class Sled : MonoBehaviour
{
public float push = 6f;
public float hop = 5f;
private Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetKey(KeyCode.RightArrow))
{
rb.AddForce(Vector3.right * push);
}
if (Input.GetKey(KeyCode.LeftArrow))
{
rb.AddForce(Vector3.left * push);
}
}
void FixedUpdate()
{
if (Input.GetKeyDown(KeyCode.Space))
{
rb.AddForce(Vector3.up * hop, ForceMode.Impulse);
}
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。