sea-battle-vr/Assets/Scripts/Settings/SettingsScreen.cs

185 lines
6.0 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SettingsScreen : MonoBehaviour
{
[Header("Управление")]
[SerializeField] private InSignal NextSetting;
[SerializeField] private InSignal PreviousSetting;
[SerializeField] private InSignal ChangeSettingPositive;
[SerializeField] private InSignal ChangeSettingNegative;
private bool controlsEnabled = true;
private bool readyToGetInput = false;
[Header("Ссылки")]
[SerializeField] private SettingGroupView GroupViewPrefab;
[SerializeField] private RectTransform pointer;
[SerializeField] private ScrollRect scrollRect;
[SerializeField] private RectTransform Content;
[Header("Настройки scroll view")]
[SerializeField] private float scrollSmoothTime = 0.2f;
private int interactionDirection = 0;
private SettingView SelectedSetting => settingsGroups[activeGroup].GeneratedSettingViews[activeSetting];
private bool Generated = false;
private int activeGroup;
private int activeSetting;
private List<SettingGroupView> settingsGroups;
// Для плавного скролла
private float targetVerticalPosition = 0f;
private float scrollVelocity = 0f;
private bool isFirstFrame = true;
private void Update()
{
if (!Generated) return;
if (isFirstFrame)
{
isFirstFrame = false;
scrollRect.verticalNormalizedPosition = 1f;
UpdateScrollTarget();
return;
}
}
private void LateUpdate()
{
if (controlsEnabled && readyToGetInput)
{
SelectedSetting.InteractView(interactionDirection);
}
SmoothScrollToSelected();
DisplayPointer();
interactionDirection = 0;
}
public void _ChangeInteractionDirection(int delta) => interactionDirection += delta;
public void EnableControls() => controlsEnabled = true;
public void DisableControls() => controlsEnabled = false;
public void SetReadyToGetInput() => readyToGetInput = true;
public void Generate()
{
// Очищаем старые группы
if (settingsGroups != null)
{
foreach (var group in settingsGroups)
{
if (group != null)
Destroy(group.gameObject);
}
}
settingsGroups = new List<SettingGroupView>();
foreach (var group in SettingsManager.currentSchemeDTO.groups)
{
var generatedGroup = GenerateGroup(group);
settingsGroups.Add(generatedGroup);
}
activeGroup = 0;
activeSetting = 0;
Generated = true;
}
public void SwitchItem(int direction)
{
if (direction == 0 || !controlsEnabled) return;
activeSetting += direction;
SettingGroupView currentGroup = settingsGroups[activeGroup];
//Выход за пределы группы (верхний предел)
if (activeSetting > currentGroup.GeneratedSettingViews.Count - 1)
{
activeGroup = (activeGroup + 1 + settingsGroups.Count) % settingsGroups.Count;
activeSetting = 0;
}
//Выход за пределы группы (нижний предел)
else if (activeSetting < 0)
{
activeGroup = (activeGroup - 1 + settingsGroups.Count) % settingsGroups.Count;
activeSetting = settingsGroups[activeGroup].GeneratedSettingViews.Count - 1;
}
UpdateScrollTarget();
}
private void DisplayPointer()
{
pointer.parent = SelectedSetting.transform;
pointer.localPosition = Vector3.zero;
}
private SettingGroupView GenerateGroup(SettingsGroupDTO group)
{
var go = Instantiate(GroupViewPrefab.gameObject, Content);
var groupView = go.GetComponent<SettingGroupView>();
groupView.Generate(group);
return groupView;
}
private void UpdateScrollTarget()
{
float targetNormalizedPosition = CalculateNormalizedPosition();
targetVerticalPosition = targetNormalizedPosition;
}
private float CalculateNormalizedPosition()
{
// Проверка наличия необходимых компонентов
if (scrollRect.viewport == null)
{
Debug.LogError("ScrollRect Viewport is not assigned!");
return 0f;
}
RectTransform selectedRect = SelectedSetting.GetComponent<RectTransform>();
// Получаем мировые координаты углов
Vector3[] worldCorners = new Vector3[4];
selectedRect.GetWorldCorners(worldCorners);
// Получаем локальные координаты относительно Content
Vector3 localPos = Content.InverseTransformPoint(worldCorners[1]); // Верхний левый угол элемента
// Вычисляем нормализованную позицию (0 = вверху, 1 = внизу)
float contentHeight = Content.rect.height;
float viewportHeight = scrollRect.viewport.rect.height;
if (contentHeight <= viewportHeight) return 0f;
float maxScroll = contentHeight - viewportHeight;
float scrollPosition = -localPos.y; // Инвертируем, т.к. UI координаты Y вниз
// Центрируем элемент
float elementHeight = selectedRect.rect.height;
scrollPosition -= (viewportHeight / 2f) - (elementHeight / 2f);
float normalizedPosition = Mathf.Clamp01(scrollPosition / maxScroll);
return 1f - normalizedPosition; // Инвертируем для ScrollRect
}
private void SmoothScrollToSelected()
{
float currentPos = scrollRect.verticalNormalizedPosition;
float newPos = Mathf.SmoothDamp(currentPos, targetVerticalPosition,
ref scrollVelocity, scrollSmoothTime);
scrollRect.verticalNormalizedPosition = newPos;
}
}