Categories: Unity

Unity:FPSController のカーソルロックを外部スクリプトから切り替える方法

今回はUnity の Standard Assets の Character アセットに含まれている FPSController のプレハブを使用して、外部スクリプトからマウスカーソルのロックを制御する方法を試してみました。

マウスカーソルロックについて

FPSの操作で必要になるマウスカーソルを画面中央に固定する機能ですが、キャラクターのインベントリ画面の操作やシステムメニューの GUI 操作時にカーソルロックを解除したいケースがあります。

通常はプレハブのコンポーネントのLock Cursor のチェックを外しておいて、別のスクリプトで制御すると大丈夫ですね。

FirstPersonControllerの場合

RigidbodyFirstPersonControllerの場合

マウス右クリックでカーソルロックを切り替えるスクリプト

新しいスクリプトを作成してマウス右クリックでカーソルロックの制御ができるようにしてみました。画面にボタンを表示してカーソルロック時は非表示になるようにしています。

スクリプト

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SwitchCursorLock : MonoBehaviour
{
    // カーソルロック判定フラグ
    private bool cursorLocked;
    // Canvas コンポーネントを格納
    public Canvas canvas;

    // ゲームスタート時の処理
    void Start()
    {
        // カーソルロックを解除
        Cursor.lockState = CursorLockMode.None;
        Cursor.visible = true;
        // カーソルロック判定フラグを無効
        cursorLocked = false;
        // Canvas コンポーネントの有効
        canvas.enabled = true;
    }

    // ゲーム実行時の繰り返し処理
    void Update()
    {
        // マウス右クリック時の処理
        if (Input.GetButtonDown("Fire2"))
        {
            // カーソルロック判定フラグが有効の場合
            if (cursorLocked)
            {
                // カーソルロックを解除
                Cursor.lockState = CursorLockMode.None;
                Cursor.visible = true;
                // カーソルロック判定フラグを無効
                cursorLocked = false;
                // Canvas コンポーネントの有効
                canvas.enabled = true;
            }
            // カーソルロック判定フラグが無効の場合
            else
            {
                // カーソルロックを実行
                Cursor.lockState = CursorLockMode.Locked;
                Cursor.visible = false;
                // カーソルロック判定フラグを有効
                cursorLocked = true;
                // Canvas コンポーネントを無効
                canvas.enabled = false;
            }
        }
    }
}

プレハブのコンポーネントから関数を呼び出してカーソルロック処理を行う

次に FPSController のスクリプトコンポーネントからカーソルロックの処理を呼び出して制御してみることにしました。まずは、プレハブのコンポーネントで使用されているスクリプトを調べてみました。

プレハブ FPSController のコンポーネント

スクリプト FirstPersonController からマウス操作のスクリプト MouseLook を呼び出しています。しかしプライベート属性になっているので、他のスクリプトからアクセスできません。

[SerializeField] private MouseLook m_MouseLook;

プレハブ RigidBodyFPSController のコンポーネント

スクリプト RigidbodyFirstPersonController からマウス操作のスクリプト MouseLook を呼び出しています。これはパブリック属性になっているので他のスクリプトからも呼び出せます。

public MouseLook mouseLook = new MouseLook();

スクリプト MouseLook のカーソルロック処理

プレハブ FPSController と RigidBodyFPSController はスクリプト MouseLook のメソッドを呼び出してカーソルロックの制御を行っています。
スクリプトのコード内でカーソルロック処理を行っているのは下記の部分です。Esc キーを押したらカーソルロック解除、マウス左ボタンクリックでカーソルロック有効になります。

public void SetCursorLock(bool value)
{
       lockCursor = value;
       if(!lockCursor)
       {//we force unlock the cursor if the user disable the cursor locking helper
           Cursor.lockState = CursorLockMode.None;
           Cursor.visible = true;
       }
}

private void InternalLockUpdate()
{
       if(Input.GetKeyUp(KeyCode.Escape))
       {
           m_cursorIsLocked = false;
       }
       else if(Input.GetMouseButtonUp(0))
       {
           m_cursorIsLocked = true;
       }
        if (m_cursorIsLocked)
       {
           Cursor.lockState = CursorLockMode.Locked;
           Cursor.visible = false;
        }
       else if (!m_cursorIsLocked)
       {
           Cursor.lockState = CursorLockMode.None;
           Cursor.visible = true;
       }
}

スクリプト

というわけで、別のスクリプトから SetCursorLock() を実行すれば、カーソルロックが制御できることが分かりました。色々試してこのようなコードが出来上がりました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// スクリプトのメソッドを使用するために名前空間を追加
using UnityStandardAssets.Characters.FirstPerson;

public class SwitchCursorLock : MonoBehaviour
{
    // rigidBodyFPSControlle オブジェクトを格納する変数
    public GameObject rbFPSCtr;
    // RigidbodyFirstPersonController スクリプトコンポーネントを格納する変数
    private RigidbodyFirstPersonController rbFPSCtrScript;
    // カーソルロック判定フラグ
    private bool cursorLocked;
    // Canvas コンポーネントを格納
    public Canvas canvas;

    // ゲームスタート時の処理
    void Start()
    {
        // RigidbodyFirstPersonController スクリプトコンポーネントを
        // 変数 rbFPSCtrScript に格納
        rbFPSCtrScript = rbFPSCtr.GetComponent<RigidbodyFirstPersonController>();
        // カーソルロックを解除
        // 変数 mouseLook に格納されたスクリプト MouseLook の
        // メソッド SetCursorLock() を実行
        rbFPSCtrScript.mouseLook.SetCursorLock(false);
        // Canvas コンポーネントを有効
        canvas.enabled = true;
    }

    // ゲーム実行時の繰り返し処理
    void Update()
    {
        // マウス右クリック時の処理
        if (Input.GetButtonDown("Fire2"))
        {
            // カーソルロック判定フラグが有効の場合
            if (cursorLocked)
            {
                // カーソルロックを解除
                // 変数 mouseLook に格納されたスクリプト MouseLook の
                // メソッド SetCursorLock() を実行
                rbFPSCtrScript.mouseLook.SetCursorLock(false);
                // カーソルロック判定フラグを無効
                cursorLocked = false;
                // Canvas コンポーネントの有効
                canvas.enabled = true;
            }
            // カーソルロック判定フラグが無効の場合
            else
            {
                // カーソルロックを実行
                // 変数 mouseLook に格納されたスクリプト MouseLook の
                // メソッド SetCursorLock() を実行
                rbFPSCtrScript.mouseLook.SetCursorLock(true);
                // カーソルロック判定フラグを有効
                cursorLocked = true;
                // Canvas コンポーネントを無効
                canvas.enabled = false;
            }
        }
    }

    // ボタンクリック時の処理
    public void Click()
    {
        // Canvas コンポーネントを無効
        canvas.enabled = false;
    }
}

StandardAssets のスクリプトは名前空間が使用されているのであらかじめ使用宣言が必要でした。今回の場合は using UnityStandardAssets.Characters.FirstPerson; となります。

WebGL

動作確認用にWebGLビルドしたものがこちらです。プレハブのインスタンス RigidBodyFPSController の Lock Curslr チェックボックスはオンのままで、外部スクリプトから制御しています。
画像クリックで再生(ファイルサイズ:約12MB)

まとめ

記事の最後で紹介したスクリプトでは、右クリックのカーソルロックと Esc キーのカーソルロックを併用すると処理が重複しているようで、切替処理の挙動が怪しいです。

結局のところ、最初の手順の通り、プレハブの Lock Curslr チェックボックスを外しておいて、カーソルロックを制御する方法が一番手っ取り早いと思いました!

また、WebGLビルドの場合は カーソルロック時にWebブラウザから
Esc キーでカーソル制御の解除」
というメッセージが表示されるので、カーソルロック切り換えのキー割り当てはそのままにしておく方が良さそうです。

corevale