using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class SettingsScreen : MonoBehaviour { public List 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 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 groups) { // Очищаем старые группы if (settingsGroups != null) { foreach (var group in settingsGroups) { if (group != null) Destroy(group.gameObject); } } settingsGroups = new List(); 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(); 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(); // Получаем мировые координаты углов 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(); } } }