物理演算のためのFixedUpdate
CoddyのUnityジャーニー「物理演算とゲームプレイ」セクションの一部。レッスン 4/71。
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つの役割を、適切なメソッドに配置しましょう。
- 矢印キーの2つの
ifブロックをUpdate()からFixedUpdate()に移動します。 private bool hopPressed;を追加します。Update()で、Input.GetKeyDown(KeyCode.Space)のときにtrueを設定します。FixedUpdate()で、hopPressedが設定されているときにインパルスを加え、その後falseに設定します。
「プレイ」を押します。矢印キーで均等に押し進み、Spaceキーを押すたびに跳びます。その後、「確認」を押します。
自分で試してみよう
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);
}
}
}
物理演算とゲームプレイのすべてのレッスン
自分で練習してみよう: Unityプレイグラウンド