Button South (A button) is set up in Player Controller to trigger the player to jump. A button also selects UI buttons in my pause menu. When in the pause menu, the player controller has input disabled. When I press A button to select the Resume UI button, the menu is disabled and an event is triggered to let the player controller class know to re-enable input. So I press A to resume the game, the moment I pressed A, the player control input should still be disabled, but a jump event still is triggered. The effect is that every time I resume gameplay from the pause menu, the player character jumps. It seems the event is queued or something, but I cannot figure out how to stop the event from being interpreted.
I have an input action asset GameInputs. I have a player controller script and a UI Manager script. For the player controller script I unsubscribe from the jump input and disable input at the same time when either the player controller game object is disabled (OnDisable) or when the UI Manager triggers a “DisablePlayerControls” event.
public class PlayerController2D : MonoBehaviour
{
GameInputs input;
private void OnEnable() // Subscribe to relevant events
{
EnableInput();
UIManager.EnablePlayerControls += EnableInput;
UIManager.DisablePlayerControls += DisableInput;
}
private void OnDisable() // unsubscribe to events
{
DisableInput();
UIManager.EnablePlayerControls -= EnableInput;
UIManager.DisablePlayerControls -= DisableInput;
}
// input events are move to their own functions to enable/disable them on Menu events
private void EnableInput()
{
if (input == null) input = new GameInputs();
input.Player.Jump.performed += JumpPerformed;
input.Player.Jump.canceled += JumpCanceled;
input.Enable();
}
private void DisableInput()
{
input.Player.Jump.performed -= JumpPerformed;
input.Player.Jump.canceled -= JumpCanceled;
input.Disable();
}
//...
// Implementation of jump action and the rest of the class
//...
}
My UIManager class will resume the game if it tries to go to a previous menu, but there are no previous menus to return to:
private void GoToPreviousMenu()
{
// disable the current menu and pop it from the stack
if (menuStack.Peek().activeInHierarchy) menuStack.Pop().SetActive(false);
// if the stack is now empty we should return to gameplay, re-enabling player control
if (menuStack.Count == 0)
{
// Player controller subscribed to this and will re-enable it's GameInputs instance.
EnablePlayerControls?.Invoke();
return;
}
// if the stack was not empty, activate the previous menu
menuStack.Peek().SetActive(true);
}
For more context, the UIManager only uses a single action from GameInputs to enable the menu when the player presses esc/start. Otherwise, I let the UI system automagically do its navigation via DefaultInputActions on the EventSystem/Input System UI Input Module, where it somehow just knows that dpad and left stick navigates, and south button (A) is select (don’t understand how this is working really either)
private void OnEnable()
{
if (input == null)
{
input = new GameInputs();
}
input.Enable();
input.Menuing.Pause.performed += EnableMainMenu;
MenuBase.Proceed += GoToNewMenu;
MenuBase.Return += GoToPreviousMenu;
}
So my confusion as previously stated is that at the moment I press A to resume, the player controller should be unsubscribed from jump events and the input should be disabled until it receives the “EnablePlayerControls” event from the UI Manager. however it still triggers “started” and “performed” events the moment control is returned.
What can I do to fix this?
Full Player Controller Class
Full UI Manager Class
EDIT (HACKY SOLUTION):
I found an incredibly hacky solution that I refuse to believe is the cleanest approach, but it technically works. I essentially just eat the first (A) input using a bool wasInMainMenu. Still seeking a proper explanation of how to do this correctly.
Delayed Input Enabling sets the bool to true:
void EnableInputOnDelay()
{
StartCoroutine(EnableInputIEnumerator());
}
IEnumerator EnableInputIEnumerator()
{
wasInMainMenu = true;
yield return new WaitForEndOfFrame();
EnableInput();
}
private void EnableInput()
{
if (input == null)
{
input = new GameInputs();
}
input.Player.Movement.performed += MovementPerformed;
input.Player.Movement.canceled += MovementCanceled;
input.Player.Attack.performed += AttackPerformed;
input.Player.Jump.performed += JumpPerformed;
input.Player.Jump.canceled += JumpCanceled;
input.Enable();
}
Jump Event Code does nothing except reset the bool to false if it was true:
private void JumpPerformed(InputAction.CallbackContext obj)
{
if(wasInMainMenu)
{
wasInMainMenu = false;
return;
}
jumpInput = true;
jumpBufferCounter = jumpBufferTime;
}



