Quick answer: Subscribe in OnEnable, unsubscribe in OnDisable. Pick one PlayerInput Behavior (SendMessages OR Invoke C# Events OR Invoke Unity Events) and don’t mix it with manual action.performed +=.
Press Jump once. Player jumps twice. Two callbacks are subscribed to the same action.
The Symptom
Single key press triggers double action. Worsens after scene reloads (more subscriptions stack). Logging the handler shows it called N times where N is the number of times OnEnable ran.
The Fix
public class Player : MonoBehaviour
{
public InputActionAsset actions;
private InputAction _jump;
void Awake()
{
_jump = actions.FindAction("Jump");
}
void OnEnable()
{
_jump.performed += OnJump;
_jump.Enable();
}
void OnDisable()
{
_jump.performed -= OnJump;
_jump.Disable();
}
void OnJump(InputAction.CallbackContext _) { /* jump */ }
}
OnEnable subscribes; OnDisable unsubscribes. Stable count of one subscription per active instance.
PlayerInput Behavior Picks One
If you use the PlayerInput component:
- SendMessages: defines OnJump(InputValue) on the script.
- Invoke Unity Events: wire UnityEvents in the inspector.
- Invoke C# Events: subscribe to playerInput.actions["Jump"].performed in code.
Pick one. Don’t both define OnJump and subscribe action.performed.
Verifying
Add Debug.Log in OnJump. Press once. Should log once. Reload the scene 5x; still logs once per press.
“Pair OnEnable + OnDisable. Pick one Behavior. No double-fire.”
Related Issues
For rebind handler leak, see rebind leak. For control scheme switch, see control scheme.
Subscribe once. Unsubscribe always.