Unity中如何禁用FPS游戏暂停时的鼠标视角控制?
Unity FPS暂停菜单:实现暂停时禁止移动但保留视角旋转与鼠标交互
我跟着Brackeys的Unity暂停菜单教程制作FPS游戏,现在遇到一个问题:暂停游戏时玩家无法移动,但我希望此时玩家仍然可以通过鼠标转动视角,同时鼠标能在菜单上正常移动,玩家脚本也能接收鼠标输入。我尝试用布尔值解决,但没成功,相关代码如下:
暂停菜单脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class PauseMenu : MonoBehaviour { public static bool GameIsPaused = false; public GameObject pauseMenuUI; void Update () { if (Input.GetKeyDown(KeyCode.Escape)) { if (GameIsPaused) { Resume( ); } else { Pause (); } } } public void Resume () { pauseMenuUI.SetActive(false); Time.timeScale = 1f; GameIsPaused = false; } void Pause () { pauseMenuUI.SetActive(true); Time.timeScale = 0f; GameIsPaused = true; } }
玩家控制器脚本
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(CharacterController))] public class PlayerController : MonoBehaviour { public float walkingSpeed = 7.5f; public float runningSpeed = 11.5f; public float jumpSpeed = 8.0f; public float gravity = 20.0f; public Camera playerCamera; public float lookSpeed = 2.0f; public float lookXLimit = 45.0f; CharacterController characterController; Vector3 moveDirection = Vector3.zero; float rotationX = 0; [HideInInspector] public bool canMove = true; void Start() { characterController = GetComponent<CharacterController>(); // Lock cursor Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } void Update() { // We are grounded, so recalculate move direction based on axes Vector3 forward = transform.TransformDirection(Vector3.forward); Vector3 right = transform.TransformDirection(Vector3.right); // Press Left Shift to run bool isRunning = Input.GetKey(KeyCode.LeftShift); float curSpeedX = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Vertical") : 0; float curSpeedY = canMove ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Horizontal") : 0; float movementDirectionY = moveDirection.y; moveDirection = (forward * curSpeedX) + (right * curSpeedY); if (Input.GetButton("Jump") && canMove && characterController.isGrounded) { moveDirection.y = jumpSpeed; } else { moveDirection.y = movementDirectionY; } // Apply gravity. Gravity is multiplied by deltaTime twice (once here, and once below // when the moveDirection is multiplied by deltaTime). This is because gravity should be applied // as an acceleration (ms^-2) if (!characterController.isGrounded) { moveDirection.y -= gravity * Time.deltaTime; } // Move the controller characterController.Move(moveDirection * Time.deltaTime); // Player and Camera rotation if (canMove) { rotationX += -Input.GetAxis("Mouse Y") * lookSpeed; rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit); playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0); transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0); } } }
解决方案
问题根源在于两点:
- 暂停时未处理鼠标锁定状态,导致鼠标无法在菜单上交互;
- 视角旋转被
canMove变量限制,且未和暂停状态做区分,同时Time.timeScale = 0会影响部分时间相关逻辑,但鼠标输入不受其影响。
1. 修改暂停菜单脚本
添加鼠标状态控制,确保暂停时解锁鼠标,恢复时重新锁定:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class PauseMenu : MonoBehaviour { public static bool GameIsPaused = false; public GameObject pauseMenuUI; void Update () { if (Input.GetKeyDown(KeyCode.Escape)) { if (GameIsPaused) { Resume(); } else { Pause(); } } } public void Resume () { pauseMenuUI.SetActive(false); Time.timeScale = 1f; GameIsPaused = false; // 恢复鼠标锁定状态 Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } void Pause () { pauseMenuUI.SetActive(true); Time.timeScale = 0f; GameIsPaused = true; // 解锁鼠标,允许菜单交互 Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } }
2. 修改玩家控制器脚本
拆分移动与视角旋转逻辑,让视角旋转不受暂停状态限制,同时调整重力计算避免暂停时失效:
using System.Collections; using System.Collections.Generic; using UnityEngine; [RequireComponent(typeof(CharacterController))] public class PlayerController : MonoBehaviour { public float walkingSpeed = 7.5f; public float runningSpeed = 11.5f; public float jumpSpeed = 8.0f; public float gravity = 20.0f; public Camera playerCamera; public float lookSpeed = 2.0f; public float lookXLimit = 45.0f; CharacterController characterController; Vector3 moveDirection = Vector3.zero; float rotationX = 0; [HideInInspector] public bool canMove = true; void Start() { characterController = GetComponent<CharacterController>(); // Lock cursor Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } void Update() { // 仅在未暂停且canMove为true时允许移动 bool allowMovement = canMove && !PauseMenu.GameIsPaused; Vector3 forward = transform.TransformDirection(Vector3.forward); Vector3 right = transform.TransformDirection(Vector3.right); bool isRunning = Input.GetKey(KeyCode.LeftShift); // 移动速度计算 float curSpeedX = allowMovement ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Vertical") : 0; float curSpeedY = allowMovement ? (isRunning ? runningSpeed : walkingSpeed) * Input.GetAxis("Horizontal") : 0; float movementDirectionY = moveDirection.y; moveDirection = (forward * curSpeedX) + (right * curSpeedY); // 跳跃逻辑 if (Input.GetButton("Jump") && allowMovement && characterController.isGrounded) { moveDirection.y = jumpSpeed; } else { moveDirection.y = movementDirectionY; } // 重力计算:使用unscaledDeltaTime避免暂停时重力停止 if (!characterController.isGrounded) { moveDirection.y -= gravity * Time.unscaledDeltaTime; } // 执行移动 if (allowMovement) { characterController.Move(moveDirection * Time.deltaTime); } // 视角旋转:不受暂停状态限制,始终允许(可根据需求调整是否保留身体旋转) rotationX += -Input.GetAxis("Mouse Y") * lookSpeed; rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit); playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0); // 暂停时可选关闭身体旋转,仅保留相机旋转 if (!PauseMenu.GameIsPaused) { transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0); } } }
核心修改说明
- 鼠标状态控制:暂停时解锁鼠标,让玩家能操作菜单;恢复时重新锁定鼠标,回归游戏操作。
- 逻辑拆分:将移动权限和视角旋转权限分离,确保暂停时视角仍可通过鼠标控制。
- 时间处理:重力计算使用
Time.unscaledDeltaTime,避免Time.timeScale = 0导致重力暂停。 - 状态关联:直接通过
PauseMenu.GameIsPaused判断暂停状态,确保移动逻辑仅在游戏运行时生效。
内容的提问来源于stack exchange,提问作者BVFreak
相关产品推荐
相关产品推荐

