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 フレーム内の順序
FixedUpdate() × N
N = 前フレームから蓄積した timestep — 通常 0 か 1、遅延時は増える
Update() — 全スクリプト
Input、AI、ゲームロジック、アニメーション
LateUpdate() — 全スクリプト
Camera follow、IK、Update 後の処理
ハンズオン手順
Update では常に Time.deltaTime を掛ける
transform.position += speed * Time.deltaTime * direction —— 秒あたり単位、FPS 非依存。
物理力 → FixedUpdate
AddForce() と velocity は FixedUpdate へ。入力は Update、適用は FixedUpdate。
カメラ追従 → LateUpdate
カメラスクリプトは LateUpdate で、プレイヤー移動後に追従——1 フレーム遅延なし。
未使用の Update を削除
空の Update にもオーバーヘッドがあります。毎フレーム不要なら Event や Coroutine を優先。
インタラクティブシミュレーター
Run を押してフレームループをステップ実行。FPS と Physics レートを調整できます。
FixedUpdate
0
calls
Update
0
calls
LateUpdate
0
calls
Render
0
frames
コード例
基本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 で適用