using System; using System.Collections.Generic; using BlueWater.Uis; using Sirenix.OdinInspector; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.UI; namespace BlueWater { public static class TutorialName { public const string TutorialA = "TutorialA"; public const string TutorialB = "TutorialB"; public const string TutorialC = "TutorialC"; public const string TutorialD = "TutorialD"; public const string TutorialE = "TutorialE"; public const string TutorialF = "TutorialF"; public const string TutorialG = "TutorialG"; public const string TutorialH = "TutorialH"; public const string TutorialI = "TutorialI"; public const string TutorialJ = "TutorialJ"; } public class TycoonTutorial : PausePopupUi { [SerializeField, Required] private GameObject _tutorialPanel; [SerializeField, Required] private GameObject _togglePanel; [SerializeField, Required] private ScrollRect _scrollRect; [SerializeField, Required] private RectTransform _buttonContents; [SerializeField, Required] private Transform _tutorialPopupUiContents; [SerializeField] private GameObject _keyAPanel; [SerializeField] private GameObject _keyDPanel; [SerializeField] private GameObject _keyEPanel; [Title("프리팹")] [SerializeField, Required] private TutorialPageToggle _tutorialPageToggle; [SerializeField, Required] private TycoonTutorialPopupUi _tutorialPopupUi; [Title("So")] [SerializeField, Required] private TutorialSo _tutorialSo; [Title("실시간 데이터")] [SerializeField] private List _tutorialLinks; [SerializeField] private TutorialLink _currentTutorialLink; private InputAction _pressQAction; private InputAction _pressRAction; private InputAction _pressAAction; private InputAction _pressDAction; private InputAction _interactionEAction; private InputAction _closeAction; private bool _isInMenu; private bool _isUpdatingToggle; public Action CloseAction; private void Start() { _pressQAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.PressQ); _pressRAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.PressR); _pressAAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.PressA); _pressDAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.PressD); _interactionEAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.InteractionE); _closeAction = PlayerInputKeyManager.Instance.GetAction(InputActionMaps.TycoonUi, TycoonUiActions.Cancel); HideUi(); foreach (Transform element in _buttonContents.transform) { Destroy(element.gameObject); } foreach (Transform element in _tutorialPopupUiContents) { Destroy(element.gameObject); } _tutorialLinks = new List(_tutorialSo.GetDataCount()); foreach (TutorialInfo tutorialInfo in _tutorialSo.GetData().Values) { TutorialPageToggle tutorialPageToggle = Instantiate(this._tutorialPageToggle, _buttonContents); List tycoonTutorialPopupUis = new List(); tutorialPageToggle.Initialize(tutorialInfo); for (int i = 0; i < tutorialInfo.TutorialPages.Count; i++) { TycoonTutorialPopupUi tycoonTutorialPopupUi = Instantiate(_tutorialPopupUi, _tutorialPopupUiContents); TutorialPageType tutorialPageType = tutorialInfo.TutorialPages[i].TutorialPageType; Sprite popupSprite = null; switch (tutorialPageType) { case TutorialPageType.First: popupSprite = _tutorialSo.FirstPopup; break; case TutorialPageType.Middle: popupSprite = _tutorialSo.MiddlePopup; break; case TutorialPageType.Last: popupSprite = _tutorialSo.LastPopup; break; case TutorialPageType.Solo: popupSprite = _tutorialSo.SoloPopup; break; default: throw new ArgumentOutOfRangeException(); } tycoonTutorialPopupUi.Initialize(tutorialInfo, i, popupSprite); tycoonTutorialPopupUis.Add(tycoonTutorialPopupUi); } TutorialLink tutorialLink = new TutorialLink(tutorialInfo.TutorialName, tutorialPageToggle, tycoonTutorialPopupUis); tutorialPageToggle.OnToggleEvent += isOn => { if (_isUpdatingToggle) return; // 이벤트 중복 방지 if (isOn) { _isUpdatingToggle = true; CloseKeyPanels(); _currentTutorialLink?.OnToggle(false); _currentTutorialLink = tutorialLink; _currentTutorialLink.OnToggle(true); UpdateKeyPanels(); FocusOnToggle(_currentTutorialLink.TutorialPageToggle); _isUpdatingToggle = false; } }; foreach (var element in tutorialLink.TycoonTutorialPopupUis) { element.SetupButtons(tutorialLink, OnMovePreviousPageButton, OnMoveNextPageButton); } _tutorialLinks.Add(tutorialLink); } _currentTutorialLink = _tutorialLinks[0]; } private void OnDestroy() { _pressQAction = null; _pressRAction = null; _pressAAction = null; _pressDAction = null; _interactionEAction = null; _closeAction = null; } public override void Open() { OpenSwitch(InputActionMaps.TycoonUi); if (_isInMenu) { SetCurrentTutorialLink(); _togglePanel.SetActive(true); UpdateKeyPanels(); _pressQAction.performed += OnMovePreviousToggle; _pressRAction.performed += OnMovNextToggle; _closeAction.performed += OnClose; } _pressAAction.performed += OnMovePreviousPage; _pressDAction.performed += OnMoveNextPage; } public override void Close() { _pressQAction.performed -= OnMovePreviousToggle; _pressRAction.performed -= OnMovNextToggle; _pressAAction.performed -= OnMovePreviousPage; _pressDAction.performed -= OnMoveNextPage; _interactionEAction.performed -= OnClose; _closeAction.performed -= OnClose; _togglePanel.SetActive(false); _tutorialPanel.SetActive(false); _currentTutorialLink?.OnToggle(false); CloseKeyPanels(); CloseAction?.Invoke(_isInMenu); _isInMenu = false; CloseSwitch(InputActionMaps.Tycoon); } public void SetCurrentTutorialLink(string tutorialName = null) { if (tutorialName == null) { _currentTutorialLink = _tutorialLinks[0]; } else { _currentTutorialLink = _tutorialLinks.Find(link => link.TutorialName == tutorialName); } _currentTutorialLink?.OnToggle(true); _tutorialPanel.SetActive(true); } public void ShowUi(bool isInMenu) { _isInMenu = isInMenu; Open(); } public void ShowUiByName(string tutorialName = null) { SetCurrentTutorialLink(tutorialName); _togglePanel.SetActive(false); UpdateKeyPanels(); ShowUi(false); } public void HideUi() { Close(); _isInMenu = false; } private void OnMovePreviousToggle(InputAction.CallbackContext context) { MoveToggle(-1); } private void OnMovNextToggle(InputAction.CallbackContext context) { MoveToggle(1); } private void MoveToggle(int direction) { CloseKeyPanels(); int currentIndex = _tutorialLinks.IndexOf(_currentTutorialLink); int nextIndex = Mathf.Clamp(currentIndex + direction, 0, _tutorialLinks.Count - 1); _currentTutorialLink.OnToggle(false); _currentTutorialLink = _tutorialLinks[nextIndex]; _currentTutorialLink.OnToggle(true); UpdateKeyPanels(); FocusOnToggle(_currentTutorialLink.TutorialPageToggle); } private void FocusOnToggle(TutorialPageToggle selectedToggle) { if (!selectedToggle.gameObject.activeInHierarchy) return; // Viewport와 Content의 너비를 가져오기 float contentWidth = _buttonContents.rect.width; // Content 전체 너비 float viewportWidth = _scrollRect.viewport.rect.width; // Viewport 너비 // 선택된 토글의 x 위치를 Content 기준으로 가져오기 float targetX = selectedToggle.Rect.anchoredPosition.x; // Normalized Position 계산 // (Content 기준 위치 - 뷰포트 절반) / (Content 너비 - 뷰포트 너비) float normalizedPosition = Mathf.Clamp01((targetX - (viewportWidth / 2)) / (contentWidth - viewportWidth)); // ScrollRect에 반영 _scrollRect.horizontalNormalizedPosition = normalizedPosition; } private void OnMovePreviousPage(InputAction.CallbackContext context) { MovePage(false); } private void OnMoveNextPage(InputAction.CallbackContext context) { MovePage(true); } private void MovePage(bool moveNext) { if (_currentTutorialLink == null) return; _currentTutorialLink.MovePage(moveNext); UpdateKeyPanels(); } public void OnMovePreviousPageButton(TutorialLink tutorialLink) { _currentTutorialLink = tutorialLink; MovePage(false); } public void OnMoveNextPageButton(TutorialLink tutorialLink) { _currentTutorialLink = tutorialLink; MovePage(true); } private void CloseKeyPanels() { _interactionEAction.performed -= OnClose; _keyAPanel.SetActive(false); _keyDPanel.SetActive(false); _keyEPanel.SetActive(false); } private void UpdateKeyPanels() { if (_currentTutorialLink == null) return; int currentPageIndex = _currentTutorialLink.CurrentPageIndex; int lastPage = _currentTutorialLink.TycoonTutorialPopupUis.Count; _keyAPanel.SetActive(currentPageIndex > 0); _keyDPanel.SetActive(currentPageIndex < lastPage - 1); if (currentPageIndex == lastPage - 1) { _keyEPanel.SetActive(true); _interactionEAction.performed += OnClose; } } private void OnClose(InputAction.CallbackContext context) { HideUi(); } } }