How to make a pause menu openable with esc in a 3d game

So I’m making a 3d rpg type game. I have a character controller and camera controller that use the mouse. It does lock and hide the cursor for camera movement. Well I do have my pause menu you script set to show the cursor but the character still takes it. I would like to be able to have a pause menu that when paused, freezes everything outside of the pause menu. I’ve attached the code of the 3 scripts below to see if there is anything i messed up on.

Player Controller Script:

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

public class PlayerController : MonoBehaviour
{
    [Header("Movement Settings")]
    [SerializeField] float moveSpeed = 5f;
    [SerializeField] float rotationSpeed = 500f;
    [SerializeField] float jumpHeight = 5f;

    /* set radius for ground check */
    [Header("Ground Check Settings")]
    [SerializeField] float groundCheckRadius = 0.2f;
    [SerializeField] Vector3 groundCheckOffset;
    [SerializeField] LayerMask groundLayer;

    private IEnumerator coroutine;

    private bool canjump = true;

    bool inAction;

    bool isGrounded;

    float ySpeed;
    Quaternion targetRotation;

    CameraController cameraController;
    Animator animator;
    CharacterController characterController;
    private void Awake()
    {
        cameraController =  Camera.main.GetComponent<CameraController>();
        animator = GetComponent<Animator>();
        characterController = GetComponent<CharacterController>();
    }
    private void Update()
    {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");

        float moveAmount = Mathf.Clamp01(Mathf.Abs(h) + Mathf.Abs(v));

        var moveInput = (new Vector3(h, 0, v)).normalized;

        var moveDir = cameraController.PlanarRotation * moveInput;

        var velocity = moveDir * moveSpeed;
        velocity.y = ySpeed;

        if (Input.GetButtonDown("Jump") && canjump && !inAction)
        {
            ySpeed = jumpHeight;
            canjump = false;
            StartCoroutine(DoJumpAnimation());
        }

        GroundCheck();
        Debug.Log("Is Grounded =" + isGrounded);
        if (isGrounded)
        {
            ySpeed = -0.5f;
            canjump = true;
        }
        else 
        {
            ySpeed += Physics.gravity.y * Time.deltaTime;
            canjump = false;
        }

        characterController.Move(velocity * Time.deltaTime);

        if (moveAmount > 0)
        {
            targetRotation = Quaternion.LookRotation(moveDir);
        }

        transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

        animator.SetFloat("moveAmount", moveAmount, 0.5f, Time.deltaTime);
    }

    void GroundCheck()
    {
        isGrounded = Physics.CheckSphere(transform.TransformPoint(groundCheckOffset), groundCheckRadius, groundLayer); 
    }

    private void OnDrawGizmosSelected()
    {
        Gizmos.color = new Color(0, 0, 1, 0.5f);
        Gizmos.DrawSphere(transform.TransformPoint(groundCheckOffset), groundCheckRadius);
    }

    IEnumerator DoJumpAnimation ()
    {
        inAction = true;


        animator.CrossFade("Jump", 0.1f);
        yield return null;

        var animState = animator.GetNextAnimatorStateInfo(0);

        yield return new WaitForSeconds(animState.length);

        inAction = false;
    }
}

Camera Controller Script:

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

public class CameraController : MonoBehaviour
{
    [SerializeField] Transform followTarget;

    /* Camera Position Fields */
    [Header("Position Settings")]
    [SerializeField] float distance = 5; /* Z */
    [SerializeField] float height = -2; /* Y */
    [SerializeField] float length = 0; /* X */

    /* Min and Max Rotation for X axis */
    [Header("Y Axis Limit Settings")]
    [SerializeField] float MinVertAng = -15;
    [SerializeField] float MaxVertAng = 45;

    /* Change Sensativity */
    [Header("Other Settings")]
    [SerializeField] float RotationSpeed = 2f;

    /* Change where camera postition is to fit better for player models. */
    [SerializeField] Vector2 framingOffset;

    /* Invert options for camera */
    [Header("Invert Camera Settings")]
    [SerializeField] bool invertX;
    [SerializeField] bool invertY;

    float rotationX;
    float rotationY;

    /* Invert Camera */
    float invertXVal;
    float invertYVal;

    private void Start()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
    }

    private void Update()
    {
        invertXVal = (invertX) ? -1 : 1;
        invertYVal = (invertY) ? -1 : 1;

        rotationX += Input.GetAxis("Camera Y") * invertYVal * RotationSpeed;
        rotationX = Mathf.Clamp(rotationX, MinVertAng, MaxVertAng);

        rotationY += Input.GetAxis("Camera X") * invertXVal * RotationSpeed;

        var targetRotation = Quaternion.Euler(rotationX, rotationY, 0);

        var focusPosition = followTarget.position + new Vector3(framingOffset.x, framingOffset.y);

        transform.position = focusPosition - targetRotation * new Vector3(length, height, distance);
        transform.rotation = targetRotation;
    }

    public Quaternion PlanarRotation => Quaternion.Euler(0, rotationY, 0);
}

Pause Enable Script:

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

public class PauseEnable : MonoBehaviour
{
    
    //Attach your canvas to this variable in inspector
    public GameObject canvasObj;

    //This will check if your game is paused (we'll set it)
    bool gamePaused;

    //Pause System - To enable mouse when you press Escape.
    void Update()
    {

        //Reading input for ESCAPE key, and by saying gamePaused = !gamePaused, we switch the bool on and off each time the Keycode is registered!
        if (Input.GetButtonDown("Cancel"))
            gamePaused = true;

        //Now we enable and disable the game object!
        if (gamePaused)
            canvasObj.SetActive(true);
        else
            canvasObj.SetActive(false);


        if (gamePaused)
        {
            Cursor.lockState = CursorLockMode.Locked;
            Cursor.visible = false;
            //All mouse / movement or other scripts
        }
        else
        {
            Cursor.lockState = CursorLockMode.None;
            Cursor.visible = true;
        }
    }
}

Edit: I am new to C# but have done other coding. I’m still learning so I don’t fully know what I’m doing with this yet. Just learning as I go.

Edit 2: Basically I want a UI that opens when escape is pressed, which allows the mouse to be used to control it. I also want to implement this for later when talking to an NPC for saving, shopping, selling, quests, etc. I need the mouse to be able to control it.

Edit 3: Also ignore some of those notes in there, it was other code i was trying and failed. Just for got to remove the notes :slight_smile:

void Update()
{
	if (Input.GetKeyDown(KeyCode.Escape))
	{
		if (canvasObj.activeSelf) // are we currently paused and showing the menu?
		{
			canvasObj.SetActive(false); // hide the menu
			Cursor.lockState = CursorLockMode.Locked; // hide cursor
			Time.timeScale=1;	// unfreeze time
		}
		else
		{
			canvasObj.SetActive(true); // show the menu
			Cursor.lockState = CursorLockMode.None; // show cursor
			Time.timeScale=0;	// freeze time
		}
	}
}
1 Like

That worked for some of it, however, when i hit resume on my pause menu it doesnt seem to go back to being able to use wasd. And the camera still moves when paused.

Edit: Never mind. Just copied some of the code to the script that handles the buttons and it worked like a charm. Thanks!