190 lines
6.0 KiB
C#
190 lines
6.0 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
|
||
public class SettingsScreen : MonoBehaviour
|
||
{
|
||
public List<SettingsGroup> TestSettingGroups;
|
||
|
||
[SerializeField] private SettingGroupView GroupViewPrefab;
|
||
[SerializeField] RectTransform pointer;
|
||
|
||
[SerializeField] private ScrollRect scrollRect;
|
||
[SerializeField] private RectTransform Content;
|
||
|
||
[Header("Настройки scroll view")]
|
||
[SerializeField] private float scrollSmoothTime = 0.2f;
|
||
[SerializeField] private bool centerSelectedItem = true; // Центрировать выбранный элемент
|
||
|
||
SettingView SelectedSetting => settingsGroups[activeGroup].GeneratedSettingViews[activeSetting];
|
||
|
||
bool Generated = false;
|
||
int activeGroup;
|
||
int activeSetting;
|
||
List<SettingGroupView> settingsGroups;
|
||
|
||
// Для плавного скролла
|
||
private float targetVerticalPosition = 0f;
|
||
private float scrollVelocity = 0f;
|
||
|
||
private void OnEnable()
|
||
{
|
||
Generate(TestSettingGroups);
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (!Generated) return;
|
||
|
||
// Навигация по элементам
|
||
if (Input.GetKeyDown(KeyCode.Space)) SwitchItem();
|
||
|
||
int dir = 0;
|
||
if (Input.GetKey(KeyCode.LeftArrow)) dir -= 1;
|
||
if (Input.GetKey(KeyCode.RightArrow)) dir += 1;
|
||
SelectedSetting.InteractView(dir);
|
||
|
||
// Плавный скролл к выбранному элементу
|
||
if (centerSelectedItem)
|
||
{
|
||
SmoothScrollToSelected();
|
||
}
|
||
DisplayPointer();
|
||
}
|
||
|
||
void SwitchItem()
|
||
{
|
||
activeSetting++;
|
||
|
||
SettingGroupView currentGroup = settingsGroups[activeGroup];
|
||
|
||
if (activeSetting > currentGroup.GeneratedSettingViews.Count - 1)
|
||
{
|
||
activeGroup = (activeGroup + 1 + settingsGroups.Count) % settingsGroups.Count;
|
||
activeSetting = 0;
|
||
}
|
||
|
||
UpdateScrollTarget();
|
||
|
||
// Отладка
|
||
Debug.Log($"Switched to Group: {activeGroup}, Setting: {activeSetting}");
|
||
}
|
||
|
||
void DisplayPointer()
|
||
{
|
||
pointer.parent= SelectedSetting.transform;
|
||
pointer.localPosition = Vector3.zero;
|
||
}
|
||
|
||
public void Generate(List<SettingsGroup> groups)
|
||
{
|
||
// Очищаем старые группы
|
||
if (settingsGroups != null)
|
||
{
|
||
foreach (var group in settingsGroups)
|
||
{
|
||
if (group != null)
|
||
Destroy(group.gameObject);
|
||
}
|
||
}
|
||
|
||
settingsGroups = new List<SettingGroupView>();
|
||
|
||
foreach (var group in groups)
|
||
{
|
||
var generatedGroup = GenerateGroup(group);
|
||
settingsGroups.Add(generatedGroup);
|
||
}
|
||
|
||
// Сброс индексов
|
||
activeGroup = 0;
|
||
activeSetting = 0;
|
||
|
||
DisplayPointer();
|
||
Generated = true;
|
||
|
||
// Обновляем канвас и скролл
|
||
Canvas.ForceUpdateCanvases();
|
||
UpdateScrollTarget();
|
||
|
||
// Принудительно применяем позицию скролла
|
||
Invoke(nameof(ApplyScrollPosition), 0.1f);
|
||
}
|
||
|
||
private SettingGroupView GenerateGroup(SettingsGroup group)
|
||
{
|
||
var go = Instantiate(GroupViewPrefab.gameObject, Content);
|
||
var groupView = go.GetComponent<SettingGroupView>();
|
||
groupView.Generate(group);
|
||
return groupView;
|
||
}
|
||
|
||
void UpdateScrollTarget()
|
||
{
|
||
if (!centerSelectedItem) return;
|
||
|
||
float targetNormalizedPosition = CalculateNormalizedPosition();
|
||
targetVerticalPosition = targetNormalizedPosition;
|
||
|
||
Debug.Log($"Target position: {targetVerticalPosition}");
|
||
}
|
||
|
||
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
|
||
}
|
||
|
||
void SmoothScrollToSelected()
|
||
{
|
||
float currentPos = scrollRect.verticalNormalizedPosition;
|
||
float newPos = Mathf.SmoothDamp(currentPos, targetVerticalPosition,
|
||
ref scrollVelocity, scrollSmoothTime);
|
||
scrollRect.verticalNormalizedPosition = newPos;
|
||
}
|
||
|
||
void ApplyScrollPosition()
|
||
{
|
||
scrollRect.verticalNormalizedPosition = targetVerticalPosition;
|
||
}
|
||
|
||
// Опционально: принудительное обновление при изменении размеров
|
||
private void OnRectTransformDimensionsChange()
|
||
{
|
||
if (Generated && centerSelectedItem)
|
||
{
|
||
Canvas.ForceUpdateCanvases();
|
||
UpdateScrollTarget();
|
||
}
|
||
}
|
||
} |