MonoBehaviour
MonoBehaviour は Unity スクリプトの基底クラスです。ライフサイクルフックや Component へのアクセスを提供し、C# コードと Unity Engine をつなぎます。Awake・Start・Update・FixedUpdate・OnDestroy の使い分けと注意点を学べます。
想像してみてください...
MonoBehaviour は Unity との雇用契約のようです。サイン(MonoBehaviour を継承)すると、従業員(スクリプト)は自動で定例会議に呼ばれます:キックオフ(Awake)、初日(Start)、毎日のスタンドアップ(Update)、物理同期(FixedUpdate)、退職面談(OnDestroy)。継承がなければ、メソッドを定義しても呼ばれません。
概念の詳細
MonoBehaviour は
Behaviour → Component → Object を継承します。この継承により Unity はリフレクション経由で
magic methods(Awake、Start、Update…)を呼び出します——
オーバーライドや base 呼び出しは不要です。
主なライフサイクル:
Awake はオブジェクト生成直後(無効でも)、
Start は有効化後の最初のフレーム、
Update は毎フレーム、FixedUpdate は Physics タイムステップ
(既定 0.02s)で走ります。
パフォーマンス: 空の Update() でも
リフレクション呼び出しのコストがあります。空の Update は削除。enabled = false で
オブジェクト全体を破棄せずライフサイクルを一時停止できます。
制限: コンストラクタ(
new MyScript())は使えません——AddComponent<T>() を使います。
スレッドセーフではない——MonoBehaviour API はメインスレッド専用です。
ダイアグラム:継承チェーンと magic methods
Awake()
内部初期化 · Start の前
Start()
初期セットアップ · 最初のフレーム
Update()
毎フレームのロジック · Input、AI...
FixedUpdate()
Physics · 0.02s ごと
LateUpdate()
全 Update の後 · Camera follow
OnEnable()
オブジェクト有効化時
OnDisable()
オブジェクト無効化時
OnDestroy()
オブジェクト破棄時
ハンズオン手順
新しい C# スクリプトを作成
Assets → Create → C# Script。コンパイルエラーを避けるためファイル名とクラス名を一致させます。
内部セットアップに Awake
コンポーネント参照のキャッシュに Awake(_rb = GetComponent<Rigidbody>())。他オブジェクトへの依存は避けます。
オブジェクト間セットアップに Start
他オブジェクトが必要なときは Start(相手の Awake は既に完了)。
Update と FixedUpdate を分ける
入力と AI → Update。物理力(AddForce、velocity)→ FixedUpdate でグリッチを防ぐ。
OnDestroy でクリーンアップ
イベント購読解除、Coroutine/タイマー停止を OnDestroy で行いリークを防ぎます。
インタラクティブシミュレーター
Play Scene を押し、ライフサイクルメソッドが順に発火するのを確認。Disable や Destroy も試せます。
Lifecycle Timeline
Console
Play を押して開始...
コード例
基本標準的な MonoBehaviour 構成と、各ライフサイクルメソッドの役割。
using UnityEngine;
public class PlayerController : MonoBehaviour
{
[SerializeField] private float speed = 5f;
private Rigidbody _rb;
private Vector3 _inputDir;
void Awake()
{
// Cache component — no dependency on other scripts
_rb = GetComponent<Rigidbody>();
}
void Start()
{
// Setup that needs GameManager.Awake to have finished
GameManager.Instance.RegisterPlayer(this);
}
void Update()
{
// Read input every frame
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
_inputDir = new Vector3(h, 0, v).normalized;
}
void FixedUpdate()
{
// Physics move — do not use Time.deltaTime here
_rb.MovePosition(_rb.position + _inputDir * speed * Time.fixedDeltaTime);
}
void OnDestroy()
{
GameManager.Instance.UnregisterPlayer(this);
}
}コード例
上級最適化:空の Update を避け、イベント購読は OnEnable/OnDisable で。
using UnityEngine;
using System;
// Full lifecycle component — pairs well with an event system
public class HealthComponent : MonoBehaviour
{
[SerializeField] private int maxHp = 100;
private int _currentHp;
public event Action<int,int> OnHealthChanged; // (current, max)
public event Action OnDied;
void Awake() => _currentHp = maxHp;
void OnEnable()
{
// Subscribe when the component becomes active
GameEvents.OnDamageDealt += TakeDamage;
}
void OnDisable()
{
// Unsubscribe immediately — avoid calls while disabled
GameEvents.OnDamageDealt -= TakeDamage;
}
public void TakeDamage(int amount)
{
_currentHp = Mathf.Max(0, _currentHp - amount);
OnHealthChanged?.Invoke(_currentHp, maxHp);
if (_currentHp == 0) OnDied?.Invoke();
}
}📌 要点
- ▸Awake = 内部、Start = オブジェクト間、Update = 毎フレーム
- ▸物理 → FixedUpdate(Update ではない)
- ▸空の Update() にもコスト——未使用なら削除
- ▸購読/解除は OnEnable/OnDisable
⚠️ よくあるミス
❌ Update() 内で GetComponent
遅い——毎フレーム検索
✅ Awake でキャッシュ:_rb = GetComponent<Rigidbody>()
❌ コンストラクタ:new PlayerCtrl()
MonoBehaviour は new 禁止——Unity が警告
✅ go.AddComponent<PlayerCtrl>()