この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:3
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: MonoBehaviour
SEOタイトル: Unity MonoBehaviour 完全ガイド

この記事の要点
  • MonoBehaviour は Unity スクリプトの基底クラス。GameObject にアタッチして動作
  • ライフサイクル: Awake → OnEnable → Start → Update / FixedUpdate / LateUpdate → OnDisable → OnDestroy
  • Update: 毎フレーム / FixedUpdate: 物理用固定間隔 / LateUpdate: カメラ追従用
  • [SerializeField] で private フィールドを Inspector に公開、public は避ける
  • 多用しすぎは禁物: 1 万個 GameObject の Update より、Manager クラスから一括処理が高速

MonoBehaviour とは

MonoBehaviour は Unity のスクリプト機能で最もよく継承する基底クラスです。これを継承した C# クラスは Unity の GameObject に Component としてアタッチでき、フレームごとに自動でメソッドが呼ばれます。

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float speed = 5f;

    void Start()
    {
        Debug.Log("Start: 初回フレーム前に呼ばれる");
    }

    void Update()
    {
        float h = Input.GetAxis("Horizontal");
        transform.Translate(Vector3.right * h * speed * Time.deltaTime);
    }
}

ライフサイクル(呼び出し順)

Unity は MonoBehaviour 派生クラスの特定のメソッド名を、ライフサイクルの各タイミングで自動的に呼び出します。

メソッド呼ばれるタイミング用途
Awake()シーン読み込み時、enabled に関係なく 1 回変数初期化、参照取得
OnEnable()GameObject が有効化されるたびイベント購読
Start()初回 Update 直前、enabled なら 1 回他オブジェクト参照ありの初期化
FixedUpdate()固定間隔(既定 0.02 秒 = 50Hz)Rigidbody 操作・物理
Update()毎フレーム入力・ゲームロジック
LateUpdate()Update 後・毎フレームカメラ追従
OnDisable()無効化される直前イベント解除
OnDestroy()削除される直前リソース解放
OnApplicationQuit()アプリ終了直前セーブ処理

Update / FixedUpdate / LateUpdate の使い分け

public class Player : MonoBehaviour
{
    public Rigidbody rb;
    public Camera cam;

    void Update()
    {
        // 入力読み取り、表示更新(フレームレートに依存)
        if (Input.GetKeyDown(KeyCode.Space))
            Jump();
    }

    void FixedUpdate()
    {
        // 物理演算(Rigidbody)は必ずここで
        rb.AddForce(Vector3.forward * 10f);
    }

    void LateUpdate()
    {
        // すべての Update 後 → カメラ追従に最適
        cam.transform.position = transform.position + new Vector3(0, 5, -10);
    }

    void Jump() => rb.AddForce(Vector3.up * 500f);
}

Inspector への公開: [SerializeField]

Unity Inspector でパラメータ調整可能にするには 2 通り:

public class Enemy : MonoBehaviour
{
    // ❌ public で公開(他クラスから書き換え可能 → カプセル化壊す)
    public float hp = 100f;

    // ✅ [SerializeField] で private のまま Inspector に公開(推奨)
    [SerializeField] private float speed = 3f;
    [SerializeField] private int damage = 10;
    [SerializeField] private GameObject explosionPrefab;

    // 範囲制限 / ツールチップも便利
    [SerializeField, Range(0f, 100f)] private float volume = 50f;
    [SerializeField, Tooltip("敵が消滅するまでの秒数")] private float lifetime = 5f;

    // 配列・リストもそのまま公開可能
    [SerializeField] private Transform[] waypoints;
}

主要なプロパティ

プロパティ意味
gameObjectアタッチされている GameObject
transform位置・回転・拡縮(gameObject.transform の省略)
enabledこのコンポーネントの ON/OFF
isActiveAndEnabledGameObject 有効 + enabled の AND
namegameObject.name の省略
taggameObject.tag の省略

Coroutine(コルーチン)

MonoBehaviour 派生クラスでのみ使える、フレームをまたぐ非同期処理:

void Start()
{
    StartCoroutine(FadeOut());
}

IEnumerator FadeOut()
{
    var renderer = GetComponent();
    Color c = renderer.material.color;
    for (float t = 0; t < 1f; t += Time.deltaTime)
    {
        c.a = 1f - t;
        renderer.material.color = c;
        yield return null;        // 次のフレームまで待つ
    }
    yield return new WaitForSeconds(1f);   // 1 秒待つ
    Destroy(gameObject);
}

// 停止
StopCoroutine(FadeOut());     // または handle 経由
StopAllCoroutines();

Invoke と InvokeRepeating

void Start()
{
    // 3 秒後に Spawn() を呼ぶ
    Invoke(nameof(Spawn), 3f);

    // 2 秒後から 1 秒間隔で繰り返し
    InvokeRepeating(nameof(Tick), 2f, 1f);

    // 解除
    CancelInvoke(nameof(Tick));
    CancelInvoke();   // すべて解除
}

void Spawn() { /* ... */ }
void Tick() { /* ... */ }

SendMessage(非推奨だが理解しておく)

// 文字列でメソッド名を指定して呼ぶ(リフレクション)
gameObject.SendMessage("TakeDamage", 10);
gameObject.BroadcastMessage("Reset");      // 子供にも
gameObject.SendMessageUpwards("OnHit");    // 親にも

// → 遅い・タイプセーフでない・リファクタしにくい
// → 推奨: GetComponent().TakeDamage(10) や Action/UnityEvent

ScriptableObject との違い

項目MonoBehaviourScriptableObject
アタッチ先GameObjectアセットファイル
Update / 物理ありなし
用途動作するゲーム要素共有データ / 設定
シーンに依存する(GameObject ごと)しない
ビルド後の保存シーン保存アセット永続
メモリ上のインスタンス数GameObject ごとアセット 1 個 = 1 インスタンス

パフォーマンスの注意

MonoBehaviour の Update 等は1 万個の GameObject にアタッチすると C++ ↔ C# の呼び出しコストが無視できなくなります。

// ❌ アンチパターン: 1万個に Update
// 各 Enemy.cs に void Update() を持つ → 10000 回 / フレームの C++→C# 呼び出し

// ✅ 推奨: Manager で一括処理
public class EnemyManager : MonoBehaviour
{
    private List enemies = new();

    void Update()
    {
        foreach (var e in enemies)
            e.Tick(Time.deltaTime);
    }
}

public class Enemy   // MonoBehaviour を継承しない POCO
{
    public void Tick(float dt) { /* ... */ }
}

// または DOTS/ECS で完全に C++ 側で処理

ECS / DOTS との比較

Unity DOTS(Data-Oriented Technology Stack)の ECS(Entity Component System) は MonoBehaviour とは別パラダイム。10 万以上のオブジェクトを高速処理するためのジョブ + バーストコンパイラ前提。

項目MonoBehaviourECS
パラダイムOOPデータ指向
メモリ配置個別アロケート連続配列 (Chunk)
並列化困難Job System で自動
学習曲線緩い急峻
大量処理遅い高速

FAQ

Q: Awake と Start の違いは?
A: Awake は GameObject が有効でなくても呼ばれ、すべての Awake の後にすべての Start が呼ばれます。「他オブジェクト参照あり初期化」は Start に書くと安全です。

Q: Update が呼ばれない
A: スペル間違い(update 小文字)、Component 無効、GameObject 無効のいずれか。Inspector でチェックボックスを確認。

Q: new MonoBehaviour() してインスタンス化できる?
A: できません。必ず GameObject に AddComponent する必要があります。gameObject.AddComponent()