using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.UI; public class SettingsScreen : MonoBehaviour, IControlable { [SerializeField] private MenuSettingsTransit _menuSettingsTransit; [Header("Ссылки")] [SerializeField] private SettingGroup GroupPrefab; private int activeSettingIndex; private List settings; [SerializeField] RectTransform _testPointer; [SerializeField] CanvasGroup _pointerCG; [SerializeField] ScrollRect scrollRect; [SerializeField] TextMeshProUGUI _description; [Header("Управление")] [SerializeField] private Axis switchAxis = Axis.Vertical; [SerializeField] private Axis interactAxis = Axis.Horizontal; [SerializeField] private PlayerAction intractButton = PlayerAction.action; [SerializeField] private float _switchRepeatInterval = 0.2f; [SerializeField] private RectTransform _rootRect; [SerializeField] private RectTransform Content; [SerializeField] RectTransform _scrollBar; private BaseSettingView SelectedSetting => settings[activeSettingIndex]; private HoldTimer _exitTimer; public bool ControlsEnabled { get; set; } = false; private bool controlsBlocked = false; private int _heldSwitchDirection; private float _nextSwitchTime; private void Start() { print("Start settings"); Generate(); UpdatePointer(); } private void OnDisable() { _exitTimer.Reset(); ResetSwitchRepeat(); } public void UpdateControls() { if(controlsBlocked && In.GetAction(JoystickSide.Both, InteractMode.Continious) == false) controlsBlocked = false; if (controlsBlocked) { ResetSwitchRepeat(); return; } int switchDirection = GetSwitchDirection(); if (switchDirection != 0) SwitchSetting(switchDirection); Vector2Int interactAxes = In.GetAxis(JoystickSide.Both, InteractMode.Continious); int interactDirection = GetAxisValue(interactAxes, interactAxis); bool action = In.GetAction(JoystickSide.Both, InteractMode.Continious); SelectedSetting.TakeInput(interactDirection, action); if(_exitTimer.Update(In.GetService())) { _menuSettingsTransit.GotoMenu(); } } private static int GetAxisValue(Vector2Int axes, Axis axis) => axis == Axis.Horizontal ? axes.x : axes.y; public void Generate() { ClearContent(); settings = new List(); foreach (var group in SettingsManager.currentSchemeDTO.groups) settings.AddRange(GenerateGroup(group).settings); _exitTimer = new HoldTimer(1); ControlsEnabled = true; } public void BlockControls() { controlsBlocked = true; ResetSwitchRepeat(); } private void SwitchSetting(int switchDirection) { SelectedSetting.Deselect(); activeSettingIndex = (activeSettingIndex + switchDirection + settings.Count) % settings.Count; SelectedSetting.Select(); _description.text = SelectedSetting.CachedSetting.Description; UpdatePointer(); } private int GetSwitchDirection() { Vector2Int switchAxes = In.GetAxis(JoystickSide.Both, InteractMode.Continious); int switchDirection = -GetAxisValue(switchAxes, switchAxis); return UpdateSwitchRepeat(switchDirection, Time.unscaledTime); } private int UpdateSwitchRepeat(int switchDirection, float currentTime) { if (switchDirection == 0) { ResetSwitchRepeat(); return 0; } if (switchDirection != _heldSwitchDirection) { _heldSwitchDirection = switchDirection; _nextSwitchTime = currentTime + _switchRepeatInterval; return switchDirection; } if (currentTime < _nextSwitchTime) return 0; _nextSwitchTime = currentTime + _switchRepeatInterval; return switchDirection; } private void ResetSwitchRepeat() { _heldSwitchDirection = 0; _nextSwitchTime = 0f; } private void UpdatePointer() { var activePivot = SelectedSetting.pivotPoint; ScrollToElementVertical(activePivot); _testPointer.position = activePivot.position; _pointerCG.alpha = SelectedSetting is SignalView ? 0 : 1; _scrollBar.anchoredPosition = new Vector2(0, -460f * activeSettingIndex / (settings.Count-1)); } private SettingGroup GenerateGroup(SettingsGroupDTO groupData) { var group = Instantiate(GroupPrefab, Content); group.Configure(groupData); return group; } private void ClearContent() { for (int i = Content.childCount - 1; i >= 0; i--) Destroy(Content.GetChild(i).gameObject); } private void ScrollToElementVertical(RectTransform targetRect) { LayoutRebuilder.ForceRebuildLayoutImmediate(scrollRect.content); RectTransform viewport = scrollRect.viewport; RectTransform content = scrollRect.content; Vector2 targetLocalPos = content.InverseTransformPoint(targetRect.position); Vector2 viewportLocalPos = content.InverseTransformPoint(viewport.position); float targetHeight = targetRect.rect.height; float viewportHeight = viewport.rect.height; float contentHeight = content.rect.height; if (contentHeight <= viewportHeight) { scrollRect.verticalNormalizedPosition = 1f; return; } float offsetY = (targetLocalPos.y - viewportLocalPos.y) * -1f; float targetCenterY = offsetY + targetHeight * 0.5f; float viewportCenterY = viewportHeight * 0.5f; float deltaY = (targetCenterY - viewportCenterY) / (contentHeight - viewportHeight); float newPosition = Mathf.Clamp01(scrollRect.verticalNormalizedPosition - deltaY); scrollRect.verticalNormalizedPosition = newPosition; } }