Input System drastically drops frames on play mode.

I am completely new to Unity. I’ve been polishing my character 2D movement scripts for a couple days and recently found out about the Input System. So naturally, I decided to give it a go and installed the package. After successfully capturing controller input and moving my character around the screen I noticed the framerate of my simple sample scene lowering, and even stopping for a few moments.

My left stick and d-pad are bound to the same action. While using them at the same time to test if this is caused due to several inputs being received at the same time I can reproduce this effect. So now I sort of know what causes it, but I do not know if it is normal.

With the old Input Manager I do not have this issue. Maybe there is some kind of optimization of some sort that I may be skipping?

The way in which I captured input in my script is the following, (mostly trying to emulate what the old Input manager does):

//Movement
InputM controls;
Vector2 stickInput;

private void Awake()
    {
       controls = new InputM();
       
    }

private void Update()
    {
         controls.Player.Movement.performed += ctx => stickInput = ctx.ReadValue<Vector2>();
         controls.Player.Movement.canceled += ctx => stickInput = Vector2.zero;
     }
private void FixedUpdate()
     {
          Move();
     }

There’s a very drastic error in your code, and I’ll outline that error at the bottom of my post.

But even without that error you’d still have lag issues with the input system, because you’re caching the Vector2 (i.e. storing the value, and then reading from it at a later point). Usually this would be fine for most cases, and in the old input system that worked just fine IIRC. But in the new input system this seems to desync what you want the result to be, so one way around this is to only read immediately when you’re using the input values.

Meaning: don’t use the cached vector.

My code was basically the same as yours (except for the Update() function), but if you instead of caching stickInput, you read directly from it when you need it, that will give you more responsiveness.

So in your code, if you’d do this (and make the appropriate changes to your Move() function) it should perform better:

//Movement
InputM controls;

private void Awake()
{
    controls = new InputM();  
}
private void FixedUpdate()
{
    Move(controls.Player.Movement.ReadValue<Vector2>());
}

I have a somewhat similar setup, and I’ve connected it to a gamepad visualizer to actually see the inputs appear on-screen. Check the first GIF I’m uploading — just spinning the control stick counter-clockwise. It seems to consistently skip a bunch of frames, even when spinning the stick slowly. Then check the second GIF — I’m using the code I posted above, and you can clearly see the difference in frame consistency between them.

Cached vector:
6731443--774829--Input System Lag.gif

Reading vector when needed:
6731443--774832--Input System Responsive.gif

################################################################

As for your “very drastic error”, here’s what’s going on in your code:

Inside your Update() function, you’re not reading anything into stickInput. You’re simply telling your script to listen to the input system’s events (“performed” and “canceled”), and perform your Move() function whenever that happens. What you’re doing, though, is telling your script to register this multiple times. So unless there’s a safeguard somewhere that prevents assigning the same function to an event several times, you’re actually assigning the Move() function to those events several times, meaning that the next time you perform any inputs, you’ll perform Move() multiple times. This will flux for every frame you play, and will inevitably overload your program. So don’t do that.

Instead, you should either cache the input inside the Update() / FixedUpdate() function, as opposed to from the input system like how you’re currently doing things. Or in this case like I explained earlier, you can read from it directly only when you need it for that extra responsiveness.

################################################################

Small addendum since you’re new to Unity:

Registering the functions to read the values is definitely the way to go when it comes to buttons and such, so doing the whole controls.Player.Movement.performed += ctx => stickInput = ctx.ReadValue<Vector2>(); wouldn’t be bad form in most cases. Except that you’d probably want to do this inside OnEnable(). And you have to also unregister these functions by swapping out the += with a -= operation inside OnDisable(). Otherwise you’re at risk of trying to run functions that no longer exist when your object is destroyed.

I’ve just fixed my code and it works perfectly. In the end the solution turned out to be a bit silly. I already had these lines:

controls.Player.Movement.performed += ctx => stickInput = ctx.ReadValue<Vector2>();
controls.Player.Movement.canceled += ctx => stickInput = Vector2.zero;

but commented in the Awake function. In a way it is similar to what you mentioned, using them in OnEnable. And I also had something similar in those two functions:

private void OnEnable()
    {
        controls.Player.Enable();
    }

    private void OnDisable()
    {
        controls.Player.Disable();

    }

I wasn’t aware what the lines of code in my Update function actually did, and didn’t realize that using them in Awake or OnEnable would let “stickInput” change dynamically. As I mentioned, I already had tried using them in Awake, but I had this problem later on and I thought I had already tried both options. Now that I understand better it is clear why my program was overloading.

For now I haven’t tried capturing the input without the cached vector. Now that my program works I’ll be playing with the system’s interactions and I’ll be sure to try reading the value directly.

Thanks for such a thorough reply!