Unityを触り始めた頃によくあるのが、Update() の中に「プレイヤー操作」「UI制御」「カーソルの表示・非表示」「ポーズ処理」など、ありとあらゆる処理を全部突っ込んでしまうパターンです。
動き始めはするのですが、少し機能を追加するたびに Update() が肥大化して、どこで何をしているのか分からなくなっていきますよね。

マウスカーソルの固定・非表示も、その「なんとなく Update() に書きがち」な処理の代表です。
そこでこの記事では、「マウスカーソルを非表示にし、ウィンドウ内にロックする」だけに責務を絞ったコンポーネント 「CursorLock」 を用意して、カーソル制御をきれいに分離してしまいましょう。

【Unity】FPSやアクションの必需品!「CursorLock」コンポーネント

以下のコンポーネントは、ゲーム開始時にカーソルを非表示&ロックし、
さらに Escキーで一時的に解除・再ロック できるようにした実用的なサンプルです。
Unity6(新Input Systemを前提としない、標準の Input クラスベース)で動作します。

フルコード


using UnityEngine;

/// <summary>
/// ゲーム開始時にマウスカーソルを非表示&ウィンドウ内にロックするコンポーネント。
/// EscキーでロックのON/OFFを切り替え可能。
/// 
/// 責務は「カーソル状態の管理」のみに限定し、
/// 入力処理やカメラ制御とは分離しておくのがポイントです。
/// </summary>
public class CursorLock : MonoBehaviour
{
    // --- 設定項目(インスペクターから調整) ---

    [Header("起動時のカーソル設定")]
    [SerializeField]
    private bool lockOnStart = true; 
    // true の場合、ゲーム開始時にカーソルをロック&非表示にする

    [Header("ロック切り替えキー")]
    [SerializeField]
    private KeyCode toggleKey = KeyCode.Escape;
    // このキーを押すたびにロックON/OFFを切り替える

    [Header("エディタ再生中のデバッグ表示")]
    [SerializeField]
    private bool showStateInConsole = false;
    // true の場合、ロック状態の変化をConsoleにログ表示する(ビルドには影響なし)

    // --- 内部状態 ---

    /// <summary>
    /// 現在カーソルがロックされているかどうか
    /// </summary>
    private bool isLocked = false;

    // --- Unityイベント ---

    private void Start()
    {
        // ゲーム開始時にロックする設定なら即ロック
        if (lockOnStart)
        {
            SetCursorLocked(true);
        }
        else
        {
            SetCursorLocked(false);
        }
    }

    private void Update()
    {
        // 指定キーが押されたらロック状態をトグル
        if (Input.GetKeyDown(toggleKey))
        {
            SetCursorLocked(!isLocked);
        }
    }

    // --- パブリックAPI ---

    /// <summary>
    /// 外部スクリプトからカーソルロックをON/OFFするための公開メソッド。
    /// 例: ポーズメニュー表示時に解除、閉じたら再ロック、など。
    /// </summary>
    /// <param name="locked">true でロック&非表示、false でロック解除&表示</param>
    public void SetCursorLocked(bool locked)
    {
        isLocked = locked;

        if (isLocked)
        {
            // カーソルをウィンドウ中央付近にロック
            Cursor.lockState = CursorLockMode.Locked;
            // カーソルを非表示
            Cursor.visible = false;
        }
        else
        {
            // ロック解除してウィンドウ内で自由に動かせるようにする
            Cursor.lockState = CursorLockMode.None;
            // カーソルを表示
            Cursor.visible = true;
        }

        if (showStateInConsole)
        {
            Debug.Log($"[CursorLock] Locked: {isLocked}, " +
                      $"LockState: {Cursor.lockState}, Visible: {Cursor.visible}");
        }
    }

    /// <summary>
    /// 現在のロック状態を取得する。
    /// 他コンポーネントが「今カーソルロック中かどうか」を知りたいときに使う。
    /// </summary>
    public bool IsLocked()
    {
        return isLocked;
    }

    // --- エディタ用補助 ---

    private void OnValidate()
    {
        // インスペクターで値を変更したときの軽いバリデーション。
        // 将来、例えば toggleKey によって UI 表示を変えたい場合などの拡張ポイントにもなる。
    }
}

使い方の手順

ここでは、典型的な FPS視点のプレイヤー を例にして使い方を見ていきます。
同じ手順で、TPSアクションマウスルック付きのカメラ にもそのまま使えます。

  1. シーンに管理用オブジェクトを作成
    – Hierarchy で右クリック → Create Empty を選択し、
    名前を GameSystemInputManager などにします。
    – このオブジェクトは「シーン全体の管理系コンポーネント」をぶら下げる用途にすると分かりやすいです。
  2. 「CursorLock」コンポーネントをアタッチ
    – 作成した空オブジェクトを選択し、
    Inspector の Add Component ボタンから CursorLock を検索して追加します。
    – もしくは、上記コードを CursorLock.cs として Assets フォルダに保存してからアタッチします。
  3. インスペクターで設定を調整
    Lock On Start:ゲーム開始と同時にロックしたいならチェックON(FPSなどは大体ON)。
    Toggle Key:デフォルトは Escape
    – 開発中に「プレイ中でもマウスを操作したい」ことが多いので、Escで解除できるのは便利です。
    Show State In Console:挙動確認したいときだけ一時的にONにすると、Consoleに状態が出て安心です。
  4. 具体的な使用例
    FPSプレイヤー:
    プレイヤーの視点回転スクリプト(例: FirstPersonCameraController)では、
    「マウス移動量を読むだけ」に責務を絞り、カーソルロックは CursorLock に任せます。
    こうすることで、将来マウス操作なしのゲームに切り替えるときも、カメラ側の修正が最小限で済みます。

    例えば、ポーズメニューを開いたときにカーソルを解放したい場合は、
    ポーズ管理コンポーネントから次のように呼び出せます。

    
    public class PauseMenu : MonoBehaviour
    {
        [SerializeField] private CursorLock cursorLock;
        [SerializeField] private GameObject pauseUI;
    
        private bool isPaused = false;
    
        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.P))
            {
                TogglePause();
            }
        }
    
        private void TogglePause()
        {
            isPaused = !isPaused;
            pauseUI.SetActive(isPaused);
    
            // ポーズ中はカーソル解放、再開したら再ロック
            cursorLock.SetCursorLocked(!isPaused);
    
            // 時間停止する場合
            Time.timeScale = isPaused ? 0f : 1f;
        }
    }
          

    敵AIのデバッグ:
    敵AIの挙動を確認するために、プレイ中にマウスでUIボタンを押したい場合、
    Escでカーソルを解放 → UI操作 → 再度Escでゲームに戻る、という流れが簡単に実現できます。

    動く床やギミックのテストシーン:
    テスト用シーンでも同じ GameSystem プレハブを使い回せば、
    毎回カーソル設定を書き直す必要がなくなり、レベルデザインに集中できます。

メリットと応用

CursorLock コンポーネントを分離しておくと、次のようなメリットがあります。

  • 責務が明確: カメラ制御やプレイヤー入力から「カーソル状態の管理」を切り離せるので、各スクリプトがシンプルになります。
  • プレハブ化しやすい: 一度設定した GameSystem オブジェクトをプレハブにしておけば、どのシーンでもドラッグ&ドロップだけで同じカーソル挙動を再利用できます。
  • レベルデザインが楽: レベルデザイナーは「このシーンではロックON」「このシーンではオフ」のように、インスペクターのチェックを切り替えるだけで挙動を変えられます。
  • 将来の仕様変更に強い: 例えば「タイトル画面ではロックしない」「マルチプレイ時はロック方法を変える」といった仕様変更が来ても、カーソル制御のコードはこのコンポーネントだけ見ればOKです。

さらに、ちょっとした改造で便利機能を足すこともできます。
例えば、ウィンドウが非アクティブになったときに自動でロック解除する処理を追加すると、Alt+Tabで別アプリに切り替えた際の操作性が向上します。


private void OnApplicationFocus(bool hasFocus)
{
    // アプリがフォーカスを失ったらカーソルを解放し、
    // フォーカスを取り戻したときに元の状態に戻す例。
    if (!hasFocus)
    {
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
    }
    else
    {
        // ゲームのロック状態に合わせて復元
        SetCursorLocked(isLocked);
    }
}

このように、小さなコンポーネントに責務を分けておくと、
「必要になったときだけ、必要な場所にだけ」改造を加えられるので、プロジェクト全体の見通しがとても良くなります。
カーソル制御で悩んでいたら、まずはこの CursorLock をベースに、自分のプロジェクト用に育てていきましょう。