0
\$\begingroup\$

I've recently set up the new Input System using Player Input component and invoke unity events. I just have one problem; I want to change the default action map to UI whenever I press the defined pause buttons because pausing won't work when the defualt map is set to Player. I want to do this via code and in PauseInput function. I tried using playerInput.SwitchCurrentActionMap but it didn't work for me. Also, I don't use a generated c# script for the player inputs. Any guidance would be appreciated.

Here's my pause menu code:

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

public class PauseMenu : MonoBehaviour
{
    public static bool GameIsPaused = false;
    public PlayerInput playerInput;
    public GameObject pauseMenuUI;
    
    public void OnPause(InputAction.CallbackContext context) {
      if (context.phase == InputActionPhase.Performed) {

          if (GameIsPaused) {
              Resume();
          } else {
             Pause();
          }
     }
}

    public void Resume()
    {
        playerInput.SwitchCurrentActionMap("Player");
        pauseMenuUI.SetActive(false);
        Time.timeScale = 1f;
        GameIsPaused = false;
    }

   public void Pause ()
    {
        playerInput.SwitchCurrentActionMap("UI");
        pauseMenuUI.SetActive(true);
        Time.timeScale = 0f;
        GameIsPaused = true;
    }
}

enter image description here As you can see, I want to change the default map from Player to UI whenever the pause button is pressed and switch back to Player whenever the button is pressed again (resume); because there can only be one active map at a time.

enter image description here

enter image description here

enter image description here

\$\endgroup\$
6
  • \$\begingroup\$ I see you've edited your question. What results do you observe with this revised code? \$\endgroup\$
    – DMGregory
    May 21 at 14:46
  • \$\begingroup\$ Yes, I stored the component in a variable and put the names in double quotation marks. I assigned all the references in the inspector and checked the events of player input to see if it is assigned or not. Still it doesn't work. Also, the weird thing here is that even if I manully set "UI" as the default map, the pause menu doesn't get activated after pressing the escape button. \$\endgroup\$
    – Ali
    May 21 at 14:49
  • \$\begingroup\$ Show us how you configured the Events section of your PlayerInput component. \$\endgroup\$
    – DMGregory
    May 21 at 15:08
  • \$\begingroup\$ I updated the question. Can this problem be related to the fact that I don't use generated C# script for the input action asset? As far as I know, there are two ways for implementing the new input system. First is generating that script and using OnEnable() and OnDisable() and the other way is much easier, using player input component and Unity events. All of my other inputs work properly using this way but I always think this might not be right and could cause some problems. \$\endgroup\$
    – Ali
    May 21 at 15:28
  • \$\begingroup\$ You failed to mention that this script causes Unity to hang and report a stack overflow. That's important information. Never leave the symptoms of the problem unstated in your question - "doesn't work" is never enough information to troubleshoot with. \$\endgroup\$
    – DMGregory
    May 21 at 16:52
1
\$\begingroup\$

Remember that the callbacks get called for multiple distinct reasons, indicated by the phase member of the action and its context:

  • Started: when interaction with the control begins (eg. the start of a hold/tap)
  • Performed: when the action has been triggered (eg. pressing a button)
  • Canceled: when the action has ended or been aborted (eg. if the player releases the button, or if the action map changes while the button is held)

So when the player presses the pause button, the following things happen:

  1. OnPause gets called with phase = InputActionPhase.Started

  2. You switch the action map before pausing the game.

  3. Switching the action map disables the "Player" version of this control and enables the "UI" version, so OnPause immediately gets called with phase = InputActionPhase.Canceled.

  4. You switch the action map before pausing the game.

  5. Switching the action map disables the "UI" version of this control and enables the "OnPause" version, so OnPause immediately gets called with phase = InputActionPhase.Canceled.

  6. We're back to step 2 again, and we loop steps 2-5 indefinitely. We never get to finish running the Pause method, because it keeps getting interrupted to send another cancelled message, leaving half-finished calls on the stack until we overflow.

So, make sure you check to see if the action is being performed before you act on it, so that you don't loop endlessly cancelling actions.

public void OnPause(InputAction.CallbackContext context) {
    if {context.phase == InputActionPhase.Performed) {

        if (GameIsPaused) {
            Resume();
        } else {
            Pause();
        }
    }
}

And don't forget to wire up your UnityEvents for both the Player and UI maps. That is, both your Player and UI maps should contain a "Pause/Unpause" action whose UnityEvent calls OnPause

\$\endgroup\$
8
  • \$\begingroup\$ Thanks for the answer. I changed the function to the one that you wrote and assigned the references but still the pause menu game object doesn't get activated. I couldn't find the root of the problem but I continue trying. I do my best to describe all the symptoms. I tried all possible situations for the UI events and noticed that after manually making it the default map, the escape button works and pause activates but only once and after that, it doesn't work anymore. Also, in this situation, the Player map doesn't work when the game starts until after pausing the game. \$\endgroup\$
    – Ali
    May 21 at 18:51
  • \$\begingroup\$ Want to edit your question to show how you configured your Player events in the inspector? You kept that part hidden the last time I asked. \$\endgroup\$
    – DMGregory
    May 21 at 18:53
  • \$\begingroup\$ I don't see a Pause action in the Player map. How do you plan to invoke the OnPause callback while using this map? \$\endgroup\$
    – DMGregory
    May 21 at 19:06
  • \$\begingroup\$ No, OnPause is in the UI map. I added an image of that. The whole point of changing the map is to access that callback which is in a different action map. \$\endgroup\$
    – Ali
    May 21 at 19:24
  • \$\begingroup\$ When you're in the UI, you call OnPause in the UI map to unpause. When you're not in the UI, in the Player map, you need an action you can trigger to pause. It won't call actions from the UI map when the Player map is active. \$\endgroup\$
    – DMGregory
    May 21 at 20:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.