-
-
Save emredesu/af597de14a4377e1ecf96b6f7b6cc506 to your computer and use it in GitHub Desktop.
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.EventSystems; | |
using UnityEngine.UI; | |
using UnityEngine.InputSystem; | |
[RequireComponent(typeof(ScrollRect))] | |
public class ScrollRectAutoScroll : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { | |
public float scrollSpeed = 10f; | |
private bool mouseOver = false; | |
private List<Selectable> m_Selectables = new List<Selectable>(); | |
private ScrollRect m_ScrollRect; | |
private Vector2 m_NextScrollPosition = Vector2.up; | |
void OnEnable() { | |
if (m_ScrollRect) { | |
m_ScrollRect.content.GetComponentsInChildren(m_Selectables); | |
} | |
} | |
void Awake() { | |
m_ScrollRect = GetComponent<ScrollRect>(); | |
} | |
void Start() { | |
if (m_ScrollRect) { | |
m_ScrollRect.content.GetComponentsInChildren(m_Selectables); | |
} | |
ScrollToSelected(true); | |
} | |
void Update() { | |
// If we are on mobile and we do not have a gamepad connected, do not do anything. | |
if (SystemInfo.deviceType == DeviceType.Handheld && Gamepad.all.Count <= 1) { | |
return; | |
} | |
// Scroll via input. | |
InputScroll(); | |
if (!mouseOver) { | |
// Lerp scrolling code. | |
m_ScrollRect.normalizedPosition = Vector2.Lerp(m_ScrollRect.normalizedPosition, m_NextScrollPosition, scrollSpeed * Time.unscaledDeltaTime); | |
} | |
else { | |
m_NextScrollPosition = m_ScrollRect.normalizedPosition; | |
} | |
} | |
#nullable enable | |
void InputScroll() { | |
if (m_Selectables.Count > 0) { | |
Keyboard? currentKeyboard = Keyboard.current; | |
Gamepad? currentGamepad = Gamepad.current; | |
if (currentKeyboard != null) { | |
if (Keyboard.current.upArrowKey.isPressed || Keyboard.current.downArrowKey.isPressed) { | |
ScrollToSelected(false); | |
} | |
} | |
if (currentGamepad != null) { | |
if (Gamepad.current.dpad.up.isPressed || Gamepad.current.dpad.down.isPressed) { | |
ScrollToSelected(false); | |
} | |
} | |
} | |
} | |
#nullable disable | |
void ScrollToSelected(bool quickScroll) { | |
int selectedIndex = -1; | |
Selectable selectedElement = EventSystem.current.currentSelectedGameObject ? EventSystem.current.currentSelectedGameObject.GetComponent<Selectable>() : null; | |
if (selectedElement) { | |
selectedIndex = m_Selectables.IndexOf(selectedElement); | |
} | |
if (selectedIndex > -1) { | |
if (quickScroll) { | |
m_ScrollRect.normalizedPosition = new Vector2(0, 1 - (selectedIndex / ((float)m_Selectables.Count - 1))); | |
m_NextScrollPosition = m_ScrollRect.normalizedPosition; | |
} | |
else { | |
m_NextScrollPosition = new Vector2(0, 1 - (selectedIndex / ((float)m_Selectables.Count - 1))); | |
} | |
} | |
} | |
public void OnPointerEnter(PointerEventData eventData) { | |
mouseOver = true; | |
} | |
public void OnPointerExit(PointerEventData eventData) { | |
mouseOver = false; | |
ScrollToSelected(false); | |
} | |
} |
Neat!
It worked for me, thanks a lot!
Rimec commented that they used scroll.verticalNormalizedPosition = (1 - ((selectedIndex / 7) / ((((float)selectables.Count) / 7) - 1)));
With 7 being the width, to make an another branch of this work with grids of 7 width.
...But I really like how your version uses input to check for vertical vs horizontal instead!
My game uses new input system and rebindable keys, so I decided to use:
if (Mathf.Abs(currContext.ReadValue().y) > Mathf.Abs(currContext.ReadValue().x))
With currContext being InputAction.CallbackContext.
That way it's not hardcoded to specific keys.
Thanks, this was the easiest one to get working in my game!
could you explain to me how you made it work with the new input system please?
I used a C# event workflow for the new input system.
In it input methods look like this: void SomeMethod (InputAction.CallbackContext context)
I just check the context to get direction.
if (context.ReadValue<Vector2>().y > 0.1f)
That's up input, since y is above 0!
(I just put it at 0.1 for a bit of extra deadzone for controllers.)
And of course for left/right you just check context.ReadValue<Vector2>().x
The reason it was "currContext" above is because my input system is on a separate script, I just stored context in that variable.
I used a C# event workflow for the new input system. In it input methods look like this:
void SomeMethod (InputAction.CallbackContext context)
I just check the context to get direction.
if (context.ReadValue<Vector2>().y > 0.1f)
That's up input, since y is above 0! (I just put it at 0.1 for a bit of extra deadzone for controllers.)And of course for left/right you just check
context.ReadValue<Vector2>().x
The reason it was "currContext" above is because my input system is on a separate script, I just stored context in that variable.
thanks for the quick reply, I tried something similar but got weird results, gonna see what I can do in the morning ,its almost midnight
Hey @caschafly, thank you for the warning!
I have fixed this issue by switching
key.wasPressedThisFrame
withkey.isPressed
. I have committed the same solution in the script, so feel free to copy-paste if you'd like.