using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; public class RulesController : MonoBehaviour, IControlable { [FormerlySerializedAs("pages")] [SerializeField] private List _pages; [SerializeField] private RectTransform _creditsContent; [SerializeField] private RectTransform _creditsViewport; [SerializeField] private TMPro.TMP_Text _sectionLabel; [SerializeField] private float _timeout = 60f; [SerializeField] private float _autoScrollSpeed = 35f; [SerializeField] private float _manualScrollSpeed = 300f; [SerializeField] private float _autoResumeDelay = 1f; private Menu _menu; private int _currentIndex; private float _lastActivityAt; private float _lastInputAt; private float _scrollOffset; public bool IsOpen { get; private set; } public bool ControlsEnabled { get; set; } private void Update() { if (!IsOpen) return; if (In.AnyButton()) _lastActivityAt = Time.unscaledTime; if (Time.unscaledTime - _lastActivityAt >= _timeout) Close(); } private void OnDisable() { if (IsOpen) Close(); } public void Open() { if (IsOpen || _pages == null || _pages.Count == 0) return; _menu = FindFirstObjectByType(FindObjectsInactive.Include); if (_menu == null || !_menu.ControlsEnabled) return; _menu.ControlsEnabled = false; _lastActivityAt = Time.unscaledTime; _lastInputAt = _lastActivityAt; _currentIndex = 0; IsOpen = true; ControlsEnabled = true; gameObject.SetActive(true); transform.SetAsLastSibling(); OpenPage(_currentIndex); ControlsPerformer.Instance.SetControlable(this); } public void Close() { if (!IsOpen) return; IsOpen = false; ControlsEnabled = false; CloseAllPages(); gameObject.SetActive(false); if (_menu != null) { _menu.ControlsEnabled = true; if (ControlsPerformer.Instance != null) ControlsPerformer.Instance.SetControlable(_menu); } } public void UpdateControls() { if (In.GetAction(JoystickSide.Both, InteractMode.Discrete)) { Close(); return; } SwitchPage(In.GetHorizontalAxis(JoystickSide.Both, InteractMode.Discrete)); if (_currentIndex != _pages.Count - 1 || _creditsContent == null) return; int direction = In.GetVerticalAxis(JoystickSide.Both, InteractMode.Continious); if (In.AnyButton()) _lastInputAt = Time.unscaledTime; float speed = direction != 0 ? -direction * _manualScrollSpeed : Time.unscaledTime - _lastInputAt >= _autoResumeDelay ? _autoScrollSpeed : 0f; float limit = Mathf.Max(0f, _creditsContent.rect.height - _creditsViewport.rect.height); if (direction == 0 && speed > 0f && _scrollOffset >= limit) _scrollOffset = 0f; _scrollOffset = Mathf.Clamp(_scrollOffset + speed * Time.unscaledDeltaTime, 0f, limit); _creditsContent.anchoredPosition = Vector2.up * _scrollOffset; } public void SwitchPage(int direction) { if (!IsOpen || direction == 0) return; _lastActivityAt = Time.unscaledTime; _currentIndex = (_currentIndex + (direction > 0 ? 1 : -1) + _pages.Count) % _pages.Count; OpenPage(_currentIndex); } private void OpenPage(int index) { CloseAllPages(); _pages[index].SetActive(true); if (_sectionLabel != null) _sectionLabel.text = index == _pages.Count - 1 ? "КОНЕЦ ИГРЫ" : "ПРАВИЛА"; _scrollOffset = 0f; _lastInputAt = Time.unscaledTime; if (_creditsContent != null) _creditsContent.anchoredPosition = Vector2.zero; if (index == _pages.Count - 1) RefreshCreditsLayout(); } private void RefreshCreditsLayout() { if (_creditsContent == null || _creditsViewport == null) return; Canvas.ForceUpdateCanvases(); float bottom = 0f; Vector3[] corners = new Vector3[4]; foreach (TMPro.TMP_Text text in _creditsContent.GetComponentsInChildren()) { RectTransform rect = text.rectTransform; float height = text.GetPreferredValues(text.text, rect.rect.width, Mathf.Infinity).y; rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, height); text.ForceMeshUpdate(); rect.GetWorldCorners(corners); for (int i = 0; i < corners.Length; i++) bottom = Mathf.Max(bottom, _creditsContent.rect.yMax - _creditsContent.InverseTransformPoint(corners[i]).y); } // Нижний отступ даёт последним строкам пройти через всю видимую область до повтора. _creditsContent.SetSizeWithCurrentAnchors( RectTransform.Axis.Vertical, bottom + _creditsViewport.rect.height); } private void CloseAllPages() { foreach (GameObject page in _pages) page.SetActive(false); } }