2

I am developing a VR application in Unity and I am struggling to develop a smooth UI scroll using my VR controller's joystick. So far what I have looks like this...

private void Update() 
{
    float joyStickDirection = globals.menuInteraction_Scroll.GetAxis(SteamVR_Input_Sources.Any).y; // this is either 1 for up or -1 for down
    if (joyStickDirection != 0) 
    {
        float multiplier = joyStickDirection * 5f; 
        scrollRect.verticalNormalizedPosition = scrollRect.verticalNormalizedPosition + (multiplier * Time.deltaTime);
    }
}

...this works, but has two problems. Firstly, it scrolls at different speeds depending how big the scrolling container is. Secondly, the scrolling is not very smooth, as it is clearly just skipping varying gaps between 0 and 1.

I think I know what's wrong but I don't have enough experience working inside Update() to figure out the correct approach. Can anyone advise?

aadu
  • 3,196
  • 9
  • 39
  • 62
  • I can also switch joyStickDirection to capture how far the joystick is pushed so it's any point from -1 to 1 instead of just -1 or 1. – aadu Nov 09 '21 at 11:27
  • Shouldn't the scroll rect work in VR the same as in non-VR? For the first issue, I would try to get the height of the box, then get the delta (multiplier * Time.deltaTime) + currentVertical position. This would give you the new position in pixel. Then newPosition / height gives you the normalized value. – fafase Nov 09 '21 at 11:31
  • My mention of the VR is just to provide context for why I am working with SteamVR and a joystick. – aadu Nov 09 '21 at 11:45

1 Answers1

2

Actually you don't necessarily go through the ScrollRect component itself.

I usually would simply do

public class ScrollExample : MonoBehaviour
{
    public float speed = 5f;

    public Transform ScrollContent;
    
    void Update()
    {
        // this is either 1 for up or -1 for down
        var joyStickDirection = globals.menuInteraction_Scroll.GetAxis(SteamVR_Input_Sources.Any).y; 
        if (joyStickDirection != 0) 
        {
            var multiplier = joyStickDirection * speed; 
            
            // You want to invert the direction since scrolling down actually means
            // moving the content up
            ScrollContent.position -= Vector3.up * multiplier * Time.deltaTime;
        }
    }
}

The ScrollRect then updates and handles the rest itself. The speed is in Units/seconds or in a Screenspace Overlay canvas in pixels per seconds regardless of how big the content is.

Usually you would want to adjust the elasticity of the ScrollRect or simply set the Movement Type to Clamped right away.

derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Thank you, this was very informative. This has solved the issue of inconsistent scroll speeds between differently sized containers. Do you have any suggestions for improving smoothness however? It is still a little jumpy, unless I set the speed very low. – aadu Nov 09 '21 at 11:58
  • 1
    You could also use interpolation ... I would however not use it on the position directly because this might screw with the elasticity of the ScrollRect too much ... but rather the input itself ... you could make the `speed` smoothly increase and decrease over time – derHugo Nov 09 '21 at 12:14