Сверстать страницы правил и подключить открытие из главного меню. Добавить управление обоими джойстиками, выход по бездействию через 60 секунд и автоматический расчёт высоты титров.
162 lines
5.3 KiB
C#
162 lines
5.3 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.Serialization;
|
|
|
|
public class RulesController : MonoBehaviour, IControlable
|
|
{
|
|
[FormerlySerializedAs("pages")]
|
|
[SerializeField] private List<GameObject> _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<Menu>(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<TMPro.TMP_Text>())
|
|
{
|
|
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);
|
|
}
|
|
}
|