On-Screen Joystick Stutter/Lag [Unity Input System Bug]

See video for issue: On-Screen Joystick Stutter/Lag [Unity Input System Bug] - YouTube

I’m using the On-Screen Joystick and Unity’s new Input System (starting from the defaut InputActions).

Basically any lag causes the movement to stutter, I don’t know if this is because the input gets set to 0 whenever the Joystick isn’t being dragged.

I’ve tested this issue on the computer (using the on-screen Joystick) where I suppose the input lag SHOULD be non-existent. Unless on-screen UI controls have some inherent lag.

Please note this is not occuring when I use WASD for movement. If I try to use Joystick on mobile, the problem is even worse

Before you ask: Yes I made sure the input system was set to Dynamic. And yes I made sure the InputAction does not have competing inputs. I have also tried switching between Update and FixedUpdate

Here’s all my code:

//My Player Controler
    public void OnMovement(InputAction.CallbackContext value)
    {
            Vector2 inputMovement = value.ReadValue<Vector2>();
            rawInputMovement = new Vector3(inputMovement.x, 0, inputMovement.y);
    }
        void CalculateMovementInputSmoothing()
    {
        smoothInputMovement = Vector3.Lerp(smoothInputMovement, rawInputMovement, Time.deltaTime * movementSmoothingSpeed);
    }
    void UpdatePlayerMovement()
    {
       mPlayerMovement.UpdateMovementData(smoothInputMovement);
    }
      void Update()
    {
        CalculateMovementInputSmoothing();
        UpdatePlayerMovement();
    }


//MyMovement Script

    void FixedUpdate()
    {
        MoveThePlayer();
    }

    void MoveThePlayer()
    {
        Vector3 movement = movementDirection * movementSpeed * Time.deltaTime;
        playerRigidbody.MovePosition(transform.position + movement);
    }

     public void UpdateMovementData(Vector3 newMovementDirection)
    {
        movementDirection = newMovementDirection;
    }

//On-Screen Joystick
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.InputSystem.Layouts;

namespace UnityEngine.InputSystem.OnScreen
{
    [AddComponentMenu("Input/On-Screen-Mod Stick")]
    public class OnScreenStickMod : OnScreenControl, IPointerDownHandler, IPointerUpHandler, IDragHandler
    {
        public void OnPointerDown(PointerEventData eventData)
        {
            if (eventData == null){
                throw new System.ArgumentNullException(nameof(eventData));
            }

            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                transform.parent.GetComponentInParent<RectTransform>(),
                eventData.position, eventData.pressEventCamera, out m_PointerDownPos);
        }

        // Movement input happens here
        public void OnDrag(PointerEventData eventData)
        {
            if (eventData == null){
                throw new System.ArgumentNullException(nameof(eventData));
            }


            RectTransformUtility.ScreenPointToLocalPointInRectangle(
                transform.parent.GetComponentInParent<RectTransform>(),
                eventData.position, eventData.pressEventCamera, out var position);
            var delta = position - m_PointerDownPos;

            delta = Vector2.ClampMagnitude(delta, movementRange);
            ((RectTransform)transform).anchoredPosition = m_StartPos + (Vector3)delta;

            var newPos = new Vector2(delta.x / movementRange, delta.y / movementRange);

            SendValueToControl(newPos);
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (eventData == null){
                throw new System.ArgumentNullException(nameof(eventData));
            }
            
            ((RectTransform)transform).anchoredPosition = m_StartPos;
            SendValueToControl(Vector2.zero);
        }

        private void Start()
        {
            m_StartPos = ((RectTransform)transform).anchoredPosition;
        }

        public float movementRange
        {
            get => m_MovementRange;
            set => m_MovementRange = value;
        }

        [FormerlySerializedAs("movementRange")]
        [SerializeField]
        private float m_MovementRange = 50;

        [InputControl(layout = "Vector2")]
        [SerializeField]
        private string m_ControlPath;

        private Vector3 m_StartPos;
        private Vector2 m_PointerDownPos;

        protected override string controlPathInternal
        {
            get => m_ControlPath;
            set => m_ControlPath = value;
        }
    }
}

FIXED IT HAHAHAHA

But I feel like there could have been a more built-in solution to this problem - I shouldn’t have to be finding workarounds to the input system to get the basic functionality that was promised

Essentially I added an event to OnPointerUp; since that one only ever fires once. Code example:

https://answers.unity.com/questions/1915288/cant-listen-to-event-invoked-inside-namespace.html?childToView=1915297#answer-1915297

If you don’t know events (they’re easy bro) then you could also look up the player by Tag and fire the method from the PlayerControler.

Feel free to give my video a like if this helps you :wink: