Unity Term Book
スクリプティングとライフサイクル

Update & Lifecycle

Unity のメインゲームループでは Update が毎フレーム、FixedUpdate が固定 Physics 刻み、LateUpdate がすべての Update の後に走ります。Time.deltaTime の正しい使い方と、カメラ追従・物理演算・入力処理に応じたフックの選び方をここで学べます。

想像してみてください...

Update は FPS に連動するアナログ時計——目に見えるもの向け:移動、入力、AI。FixedUpdate は一定ビート(0.02s)のデジタル時計——物理用で動きがガタつかない。LateUpdate は最後——カメラは全員が動いてから追従し、1 フレームの遅れを防ぎます。

概念の詳細

Update() は毎フレーム——頻度は FPS (30、60、120…)に従います。移動/速度に Time.deltaTime を掛け、 フレームレート間で結果を一定にします。

FixedUpdate()Time.fixedDeltaTime (既定 0.02s = 毎秒 50 回)で走ります。FPS 非依存。 Rigidbody.AddForce()Rigidbody.velocity、物理クエリに使います。 1 レンダーフレームに FixedUpdate は 0、1、または複数回対応します。

LateUpdate() はそのフレームの全スクリプト Update() の後に走ります。 Camera 追従(プレイヤーは既に移動済み)、IK、Update 後の結果を「読む」ロジックに最適です。

OnGUI() はレガシーです。 Update vs Coroutine: 一度きりや遅延ロジックは、 Update での毎フレームポーリングより Coroutine を優先します。

ダイアグラム:1 フレーム内の順序

⏰ Physics Timestep Accumulation

FixedUpdate() × N

N = 前フレームから蓄積した timestep — 通常 0 か 1、遅延時は増える

📥 Input Processing

Update() — 全スクリプト

Input、AI、ゲームロジック、アニメーション

LateUpdate() — 全スクリプト

Camera follow、IK、Update 後の処理

🎨 Rendering (Culling → Drawing → PostFX)

ハンズオン手順

1

Update では常に Time.deltaTime を掛ける

transform.position += speed * Time.deltaTime * direction —— 秒あたり単位、FPS 非依存。

2

物理力 → FixedUpdate

AddForce()velocity は FixedUpdate へ。入力は Update、適用は FixedUpdate。

3

カメラ追従 → LateUpdate

カメラスクリプトは LateUpdate で、プレイヤー移動後に追従——1 フレーム遅延なし。

4

未使用の Update を削除

空の Update にもオーバーヘッドがあります。毎フレーム不要なら Event や Coroutine を優先。

インタラクティブシミュレーター

Run を押してフレームループをステップ実行。FPS と Physics レートを調整できます。

FixedUpdate

0

calls

Update

0

calls

LateUpdate

0

calls

Render

0

frames

Current step: Idle
Frame: 0|Time: 0.00s|Phase: Stopped

コード例

基本

Update・FixedUpdate・LateUpdate にロジックを正しく分割する。

public class PlayerMovement : MonoBehaviour
{
  [SerializeField] private float speed      = 5f;
  [SerializeField] private float jumpForce  = 8f;
  private Rigidbody _rb;
  private Vector3   _moveDir;
  private bool      _jumpRequest;

  void Awake() => _rb = GetComponent<Rigidbody>();

  void Update()
  {
      // Input — every frame, store for FixedUpdate
      float h = Input.GetAxisRaw("Horizontal");
      float v = Input.GetAxisRaw("Vertical");
      _moveDir = new Vector3(h, 0, v).normalized;

      if (Input.GetButtonDown("Jump")) _jumpRequest = true;
  }

  void FixedUpdate()
  {
      // Apply physics — do not use Time.deltaTime here
      _rb.velocity = new Vector3(_moveDir.x * speed, _rb.velocity.y, _moveDir.z * speed);

      if (_jumpRequest)
      {
          _rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
          _jumpRequest = false;
      }
  }
}

public class CameraFollow : MonoBehaviour
{
  [SerializeField] private Transform target;
  [SerializeField] private Vector3   offset = new Vector3(0, 5, -8);

  void LateUpdate()
  {
      // After target.Update() — target pose is final
      transform.position = Vector3.Lerp(transform.position,
          target.position + offset, Time.deltaTime * 5f);
  }
}

コード例

上級

毎フレーム不要なロジックは Update より Coroutine を優先。

public class EnemyAI : MonoBehaviour
{
  private Transform _player;
  private float _attackCooldown = 2f;

  void Start()
  {
      _player = GameObject.FindWithTag("Player").transform;
      // AI tick every 0.2s instead of every frame → saves CPU
      StartCoroutine(AIUpdateLoop());
      StartCoroutine(AttackLoop());
  }

  // Run AI logic 5×/sec instead of 60×/sec
  private IEnumerator AIUpdateLoop()
  {
      var wait = new WaitForSeconds(0.2f);
      while (true)
      {
          UpdatePathfinding();
          yield return wait;
      }
  }

  private IEnumerator AttackLoop()
  {
      while (true)
      {
          yield return new WaitForSeconds(_attackCooldown);
          if (Vector3.Distance(transform.position, _player.position) < 3f)
              Attack();
      }
  }
}

📌 要点

  • Update 内の移動はすべて * Time.deltaTime
  • 物理の force/velocity → FixedUpdate(deltaTime 不要な場合が多い)
  • カメラ追従 → LateUpdate(プレイヤー移動を待つ)
  • 疎なロジック → Coroutine + WaitForSeconds

⚠️ よくあるミス

  • ❌ FixedUpdate で Time.fixedDeltaTime なしに transform 移動

    速度が物理レート依存——不安定

    ✅ Time.fixedDeltaTime を掛けるか MovePosition() を使う

  • ❌ FixedUpdate 内で Input を読む

    速いフレームで GetKeyDown を取りこぼす

    ✅ Input は Update、フラグを保存し FixedUpdate で適用