今回はUnity の Standard Assets の Character アセットに含まれている FPSController のプレハブを使用して、外部スクリプトからマウスカーソルのロックを制御する方法を試してみました。
FPSの操作で必要になるマウスカーソルを画面中央に固定する機能ですが、キャラクターのインベントリ画面の操作やシステムメニューの GUI 操作時にカーソルロックを解除したいケースがあります。
通常はプレハブのコンポーネントのLock Cursor のチェックを外しておいて、別のスクリプトで制御すると大丈夫ですね。
新しいスクリプトを作成してマウス右クリックでカーソルロックの制御ができるようにしてみました。画面にボタンを表示してカーソルロック時は非表示になるようにしています。
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 のスクリプトコンポーネントからカーソルロックの処理を呼び出して制御してみることにしました。まずは、プレハブのコンポーネントで使用されているスクリプトを調べてみました。
スクリプト FirstPersonController からマウス操作のスクリプト MouseLook を呼び出しています。しかしプライベート属性になっているので、他のスクリプトからアクセスできません。
[SerializeField] private MouseLook m_MouseLook;
スクリプト RigidbodyFirstPersonController からマウス操作のスクリプト MouseLook を呼び出しています。これはパブリック属性になっているので他のスクリプトからも呼び出せます。
public MouseLook mouseLook = new 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ビルドしたものがこちらです。プレハブのインスタンス RigidBodyFPSController の Lock Curslr チェックボックスはオンのままで、外部スクリプトから制御しています。
画像クリックで再生(ファイルサイズ:約12MB)
記事の最後で紹介したスクリプトでは、右クリックのカーソルロックと Esc キーのカーソルロックを併用すると処理が重複しているようで、切替処理の挙動が怪しいです。
結局のところ、最初の手順の通り、プレハブの Lock Curslr チェックボックスを外しておいて、カーソルロックを制御する方法が一番手っ取り早いと思いました!
また、WebGLビルドの場合は カーソルロック時にWebブラウザから
「 Esc キーでカーソル制御の解除」
というメッセージが表示されるので、カーソルロック切り換えのキー割り当てはそのままにしておく方が良さそうです。