-
-
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); | |
} | |
} |
Hey @caschafly, thank you for the warning!
I have fixed this issue by switching key.wasPressedThisFrame
with key.isPressed
. I have committed the same solution in the script, so feel free to copy-paste if you'd like.
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
Hi there
Thank you so much for the script.
Just notice that the input can hold, for example the arrow button, and the scroll will not move even when the select button is switched to the next one. is there any way to fix it? sorry for my poor English, and I hope I have explained it clearly.
Looking forward to your help, thank you so much!