189 lines
6.1 KiB
C#
189 lines
6.1 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;
|
||
|
||
[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 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;
|
||
}
|
||
|
||
if (_controlsEnabled)
|
||
{
|
||
int dir;
|
||
// Навигация по настройкам
|
||
dir = 0;
|
||
if (In.GetButtonDown(PreviousSetting)) dir -= 1;
|
||
if (In.GetButtonDown(NextSetting)) dir += 1;
|
||
SwitchItem(dir);
|
||
|
||
//Взаимодействие с настройками
|
||
dir = 0;
|
||
if (In.GetButton(ChangeSettingNegative)) dir -= 1;
|
||
if (In.GetButton(ChangeSettingPositive)) dir += 1;
|
||
SelectedSetting.InteractView(dir);
|
||
}
|
||
|
||
SmoothScrollToSelected();
|
||
DisplayPointer();
|
||
}
|
||
|
||
public void EnableControls() => _controlsEnabled = true;
|
||
public void DisableControls() => _controlsEnabled = false;
|
||
|
||
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;
|
||
}
|
||
|
||
private void SwitchItem(int direction)
|
||
{
|
||
if (direction == 0) 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;
|
||
}
|
||
} |