Input System Advice (Reading axis data)

Hello everyone,

As stated in the Input System Manual “Input Actions are designed to separate the logical meaning of an input from the physical means of input… You can write code that is agnostic to where the input is coming from”.

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Actions.html

I’m currently converting from the old input system in order to make use of this modularity, so instead of reading e.g. gamepad axis data like:

A: look = gamepad.rightStick.ReadValue();

I try to:

B: myControls.gameplay.look.performed +=

        context => look = context.ReadValue<Vector2>();

While case A provides a constant input reading it lacks the modularity, making it necessary to write device specific code. Case B on the other hand provides the device independency but appears to limit its capabilities primarily because (I assume) it’s based on state of events.

In other words I find it hard to comprehend how an event would be generated if, for example, a gamepad stick is held still at some percentage away from the center. It seems like in practice, small stick movements generate “.performed” events which seem to be as inconsistent as the gamepads’ internal mechanism jitter, making the overall response appear non-linear.

Further down the Input System manual another method of reading events is described:

https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Events.html

In the “Reading State Event” section the following code is suggested for reading directly from devices using event pointers.

InputSystem.onEvent +=
    (eventPtr, device) =>
    {
        // Ignore anything that isn't a state event.
        if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>())
            return;
        var gamepad = device as Gamepad;
        if (gamepad == null)
        {
            // Event isn't for a gamepad or device ID is no longer valid.
            return;
        }
        var leftStickValue = gamepad.leftStick.ReadValueFromEvent(eventPtr);
    };

In this case the data reading seems consistent but I can’t find a way to associate this with the actual Action (e.g. typical Move or Aim).

How should I approach this matter? Can I keep both the modularity and the responsiveness?

Thanks for reading!

1 Like

Here’s an example of some movement code I have in my project. Working with both keyboard input and gamepad input.

MovementProcessor.cs

[SerializeField] private float movementSensitivity;
public Vector2 RawInput => rawInput;
private InputMap _inputMap;
private Vector2 rawInput;
     

        public void OnEnable()
        {
            if (_inputMap == null)
                _inputMap = new InputMap();

            _inputMap.Player.Move.Enable();
            _inputMap.Player.Move.performed += ctx => rawInput = ctx.ReadValue<Vector2>().normalized * movementSensitivity;
            _inputMap.Player.Move.canceled += ctx => rawInput = Vector2.zero;
        }
    }

Then inside my movement script I simply do
TopDown_Camera.cs

        private void BuildInput()
        {
            input = new Vector3(_processor.RawInput.x, _pointerData.Scroll.y, _processor.RawInput.y);
        }

        private void MoveObject()
        {
            transform.position = Vector3.SmoothDamp(transform.position, transform.position + input, ref velocity,
                Time.smoothDeltaTime);
        }

        private void FixedUpdate()
        {
            BuildInput();
            MoveObject();
        }

and here is what my input asset looks like for that action.

Here’s another example where I apply a shift modifier, but it could feasibly be the trigger on a gamepad causing this action to fire.

            _inputMap.Player.ShiftModifier.Enable();
            _inputMap.Player.ShiftModifier.performed += ctx => ShiftModifier = true;
            _inputMap.Player.ShiftModifier.canceled += ctx => ShiftModifier = false;

Then in the movement script, again I simply do

         if (_processor.ShiftModifier)
                input *= modifedPanSpeed;

Thanks for your reply @FullMe7alJacke7 , I like your approach. It seems you have identified the same issue and this means we’re on the same page. I have tried your example and i must say, with the smoothDamp you apply on the input, things get a little better. Especially with high values of deltaTime. On the other hand though this creates unnecessary input lag, because of averaging.

I wouldn’t accept it as a proper solution as it “mends” the issue and does not “cure” it. I wonder if there is a proper solution to this and I’m curius as to why isn’t this thing referenced in the official documentation. I believe it is a really important matter which makes me wonder whether I miss some cruicial information from somewhere.

1 Like

@FullMe7alJacke7 it doesn’t look like there’s a definition for InputMap; was that something unique to your project?

1 Like

Yes, InputMap is what I call my generated C# script from the input settings SO

Using the Time.smoothDeltaTime helps things too. It technically does add input lag as you say, but I doubt it would really be noticeable, even in super fast paced gameplay. I do it this way as it allows for much more separation of code.

I’ve expanded upon this since posting. When I get the rotation finished I will post an update. There are many ways you can handle the values from the new system which is what makes it so nice; There is a lot more control and flexibility there while still being easy to code and has cross platform input support.

There are also more settings in the Project Settings window. Perhaps playing with the code and the “Update Mode” will help you reach your goal.

EDIT: Also this video was a nice overview if you haven’t watched it
https://www.youtube.com/watch?v=gVus9PqfgAM

Thanks @FullMe7alJacke7 , I ended up monitoring input axes using the standard ReadValue() inside the FixedUpdate(). I then added a state machine to swap control modes (mouse/keyboard, controller) using the InputUser.onChange event. The rest of the controlls are just buttons, both for keyboard and gamepad, so I left the new input system and it’s events. So basically other than any axes the rest of the controls are common for all devices.

1 Like