概要
Unityのスクリプティングにおいて、Update()は最もよく使われる関数の一つですが、それと非常によく似たFixedUpdate()という関数も存在します。この二つはどちらも繰り返し処理を実行するために使われますが、その実行タイミングと主な用途には決定的な違いがあります。
この違いを理解せずに両者を混同してしまうと、キャラクターの動きがカクついたり、物理演算が不安定になったりするなど、様々な問題の原因となります。この記事では、Update()とFixedUpdate()のそれぞれの役割を明確にし、どのような場合にどちらを使うべきなのか、その正しい使い分けについて詳しく解説します。
実行タイミングの違い
Update()とFixedUpdate()の最も重要な違いは、呼び出されるタイミングです。
Update()
- 毎フレーム1回呼び出されます。
- 実行間隔はフレームレートに依存します。つまり、PCの性能が高く、ゲームが秒間120フレーム(120fps)で動作していれば1秒間に120回、性能が低く30fpsしか出なければ1秒間に30回呼ばれます。実行間隔は一定ではありません。
FixedUpdate()
- 固定された時間間隔で呼び出されます。
- この間隔はデフォルトで0.02秒に設定されており、
Edit > Project Settings > TimeのFixed Timestepから変更できます。 - 実行間隔はフレームレートに依存しません。常に一定の間隔で呼び出されることが保証されています。
フレームレートが高い場合、Update()が数回呼ばれた後にFixedUpdate()が1回呼ばれる、という状況が発生します。逆にフレームレートが低い場合は、1フレームの間にFixedUpdate()が複数回呼ばれることもあります。
用途の使い分け
この実行タイミングの違いから、それぞれの用途は明確に分かれています。
Update()の主な用途
フレームごとに状態が変化する可能性のある、時間的制約の少ない処理に適しています。Updateはフレームの描画と同期しているため、見た目に関する処理や入力の取得に最適です。
- 入力処理:
Input.GetKey()やInput.GetMouseButtonDown()など、プレイヤーからの入力を毎フレームチェックする。 - キャラクターの移動(物理演算を使わない場合):
transform.Translate()を使った単純な移動処理。 - タイマーやクールダウンの実装
- UIの更新
Update内で移動処理などを行う際は、Time.deltaTime を乗算することを忘れないでください。Time.deltaTimeは、前のフレームから現在のフレームまでにかかった時間を表します。これを移動量に乗算することで、フレームレートが変動しても移動速度を一定に保つことができます。
using UnityEngine;
public class SimplePlayerMovement : MonoBehaviour
{
public float speed = 5f;
void Update()
{
// 入力を受け取る
float horizontal = Input.GetAxis("Horizontal"); // -1.0f から 1.0f
// Time.deltaTimeを乗算して、フレームレートに依存しない移動を実現
transform.Translate(Vector3.right * horizontal * speed * Time.deltaTime);
}
}
FixedUpdate()の主な用途
実行間隔が保証されているため、物理演算に関連する処理はすべてFixedUpdate()で行うのが鉄則です。Unityの物理エンジン(PhysX)は、FixedUpdate()のタイミングに合わせて更新処理を行っているためです。
Rigidbodyへの力の適用:rb.AddForce()やrb.AddTorque()を使ってオブジェクトに力を加える。Rigidbodyの速度の変更:rb.velocityを直接変更する。- 物理的なキャラクターコントローラーの実装
もしUpdate()内でRigidbodyに力を加え続けると、フレームレートの変動によって力が加わる回数が変わり、結果としてオブジェクトの動きが不安定になってしまいます。FixedUpdate()を使えば、常に一定の間隔で力が加わるため、再現性の高い安定した物理挙動が実現できます。
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PhysicsPlayerMovement : MonoBehaviour
{
public float moveForce = 50f;
private Rigidbody rb;
void Awake()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
// 入力を受け取る
float horizontal = Input.GetAxis("Horizontal");
// Rigidbodyに力を加えて移動させる
rb.AddForce(Vector3.right * horizontal * moveForce);
}
}
まとめ
Update()とFixedUpdate()の使い分けは、Unityにおけるパフォーマンスと挙動の安定性を左右する重要なポイントです。以下のルールを常に意識しましょう。
Update() | FixedUpdate() | |
|---|---|---|
| タイミング | フレームごと(可変) | 固定時間ごと(一定) |
| 主な用途 | 入力処理、非物理的な移動、ゲームロジック | Rigidbodyを使った物理演算 |
| 注意点 | Time.deltaTimeを使う | Time.deltaTimeは不要(自動で考慮される) |
「物理演算はFixedUpdate、それ以外はUpdate」
このシンプルな原則を覚えておけば、多くの問題を未然に防ぐことができます。それぞれの関数の役割を正しく理解し、適切な場所にコードを記述する習慣をつけましょう。