271 lines
8.8 KiB
C#
271 lines
8.8 KiB
C#
![]() |
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Linq;
|
||
|
using UnityEngine;
|
||
|
|
||
|
namespace DDD
|
||
|
{
|
||
|
public enum TabGroupType
|
||
|
{
|
||
|
None = 0,
|
||
|
InventoryCategory,
|
||
|
SectionCategory
|
||
|
}
|
||
|
|
||
|
public enum TabButtonType
|
||
|
{
|
||
|
None = 0,
|
||
|
SectionButtonType,
|
||
|
MenuButtonType, // Menu 그룹용 (Food, Drink, Ingredient)
|
||
|
CookwareButtonType, // Cookware 그룹용 (Cookware, Special, Ingredient)
|
||
|
WorkerButtonType // Worker 그룹용 (필요시 확장)
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 공통 탭 그룹 UI 클래스
|
||
|
/// 제네릭 없이 탭을 관리합니다.
|
||
|
/// </summary>
|
||
|
public class CommonTabGroupUi : MonoBehaviour
|
||
|
{
|
||
|
[Header("정적 배치된 탭 버튼들")]
|
||
|
[SerializeField] private List<CommonTabButtonUi> _tabButtons = new();
|
||
|
|
||
|
[Header("탭 버튼 타입 설정")]
|
||
|
[SerializeField] private TabButtonType _tabButtonType = TabButtonType.None;
|
||
|
|
||
|
private Dictionary<int, CommonTabButtonUi> _tabLookup = new();
|
||
|
|
||
|
// 그룹별 기본 허용 값 정의 (List<int>로 통일하여 일관성 확보)
|
||
|
private static readonly Dictionary<TabButtonType, List<int>> TabButtonConfig = new()
|
||
|
{
|
||
|
{ TabButtonType.SectionButtonType, new List<int> {
|
||
|
(int)SectionButtonType.Menu,
|
||
|
(int)SectionButtonType.Cookware,
|
||
|
(int)SectionButtonType.Worker
|
||
|
}},
|
||
|
{ TabButtonType.MenuButtonType, new List<int> {
|
||
|
(int)InventoryCategoryType.Food,
|
||
|
(int)InventoryCategoryType.Drink,
|
||
|
(int)InventoryCategoryType.Ingredient
|
||
|
}},
|
||
|
{ TabButtonType.CookwareButtonType, new List<int> {
|
||
|
(int)InventoryCategoryType.Cookware,
|
||
|
(int)InventoryCategoryType.Special,
|
||
|
(int)InventoryCategoryType.Ingredient
|
||
|
}},
|
||
|
{ TabButtonType.WorkerButtonType, new List<int> { } }
|
||
|
};
|
||
|
|
||
|
public int CurrentTabValue { get; private set; }
|
||
|
public int TabCount => _tabButtons.Count;
|
||
|
|
||
|
public event Action<int> OnTabSelected;
|
||
|
|
||
|
private void OnDestroy()
|
||
|
{
|
||
|
if (_tabButtons == null) return;
|
||
|
|
||
|
foreach (var tabButton in _tabButtons)
|
||
|
{
|
||
|
if (tabButton != null)
|
||
|
{
|
||
|
tabButton.OnTabClicked -= HandleTabButtonClicked;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Initialize(Action<int> onTabSelected)
|
||
|
{
|
||
|
if (onTabSelected != null)
|
||
|
{
|
||
|
OnTabSelected += onTabSelected;
|
||
|
}
|
||
|
|
||
|
InitializeTabs();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 기본 허용 값들을 사용하여 탭을 초기화합니다.
|
||
|
/// </summary>
|
||
|
public void UseDefaultAllowedValues()
|
||
|
{
|
||
|
if (TabButtonConfig.TryGetValue(_tabButtonType, out List<int> defaultValues))
|
||
|
{
|
||
|
// 기본값을 바로 사용하여 탭 초기화
|
||
|
InitializeTabsWithValues(defaultValues);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"TabButtonType {_tabButtonType}에 대한 설정이 정의되지 않았습니다.", this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 지정된 값들로 탭들을 초기화합니다.
|
||
|
/// </summary>
|
||
|
public void InitializeTabsWithValues(List<int> allowedValues)
|
||
|
{
|
||
|
if (allowedValues == null || allowedValues.Count == 0)
|
||
|
{
|
||
|
Debug.LogWarning("허용된 값이 설정되지 않았습니다.", this);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 탭 버튼들과 허용된 값들을 연결
|
||
|
for (int i = 0; i < Mathf.Min(allowedValues.Count, _tabButtons.Count); i++)
|
||
|
{
|
||
|
var enumValue = allowedValues[i];
|
||
|
var tabButton = _tabButtons[i];
|
||
|
|
||
|
if (tabButton != null)
|
||
|
{
|
||
|
// 탭 버튼 데이터 설정
|
||
|
tabButton.SetTabData(enumValue);
|
||
|
|
||
|
// 클릭 이벤트 설정 (add/remove 패턴 사용)
|
||
|
tabButton.OnTabClicked += HandleTabButtonClicked;
|
||
|
|
||
|
// 딕셔너리에 추가
|
||
|
_tabLookup[enumValue] = tabButton;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 탭들을 설정하고 초기화합니다.
|
||
|
/// </summary>
|
||
|
private void InitializeTabs()
|
||
|
{
|
||
|
if (_tabButtons == null || _tabButtons.Count == 0)
|
||
|
{
|
||
|
Debug.LogWarning("탭 버튼들이 설정되지 않았습니다.", this);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 기본값을 사용하여 탭 초기화
|
||
|
if (TabButtonConfig.TryGetValue(_tabButtonType, out List<int> defaultValues))
|
||
|
{
|
||
|
InitializeTabsWithValues(defaultValues);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Debug.LogWarning($"TabButtonType {_tabButtonType}에 대한 설정이 정의되지 않았습니다.", this);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 탭 버튼 클릭 이벤트 처리
|
||
|
/// </summary>
|
||
|
private void HandleTabButtonClicked(int tabValue)
|
||
|
{
|
||
|
SelectTab(tabValue);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 지정된 값을 가진 탭을 선택합니다.
|
||
|
/// </summary>
|
||
|
public void SelectTab(int tabValue)
|
||
|
{
|
||
|
if (_tabLookup == null || _tabLookup.Count == 0)
|
||
|
{
|
||
|
Debug.LogWarning("탭 룩업이 초기화되지 않았습니다.", this);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!_tabLookup.ContainsKey(tabValue))
|
||
|
{
|
||
|
Debug.LogWarning($"탭 값 {tabValue}에 해당하는 탭을 찾을 수 없습니다.", this);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CurrentTabValue = tabValue;
|
||
|
|
||
|
// 모든 탭의 선택 상태 업데이트
|
||
|
foreach (var tabValueButton in _tabLookup)
|
||
|
{
|
||
|
tabValueButton.Value.SetSelected(tabValueButton.Key == tabValue);
|
||
|
}
|
||
|
|
||
|
// 이벤트 호출
|
||
|
OnTabSelected?.Invoke(tabValue);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 첫 번째 탭을 선택합니다.
|
||
|
/// </summary>
|
||
|
public void SelectFirstTab()
|
||
|
{
|
||
|
if (_tabButtons == null || _tabButtons.Count == 0) return;
|
||
|
if (_tabButtons[0] != null)
|
||
|
{
|
||
|
var firstTabValue = _tabButtons[0].TabValue;
|
||
|
SelectTab(firstTabValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 현재 탭에서 지정된 방향으로 이동합니다.
|
||
|
/// </summary>
|
||
|
public void Move(int direction)
|
||
|
{
|
||
|
if (_tabButtons == null || _tabButtons.Count == 0) return;
|
||
|
if (_tabLookup == null || _tabLookup.Count == 0) return;
|
||
|
|
||
|
// 성능 최적화: List 생성 대신 직접 반복
|
||
|
var tabValues = _tabLookup.Keys.ToArray();
|
||
|
int currentIndex = Array.IndexOf(tabValues, CurrentTabValue);
|
||
|
|
||
|
if (currentIndex == -1) return;
|
||
|
|
||
|
// 상호작용 가능한 탭으로만 이동
|
||
|
int newIndex = currentIndex;
|
||
|
int attempts = 0;
|
||
|
int maxAttempts = tabValues.Length; // 무한 루프 방지
|
||
|
|
||
|
do
|
||
|
{
|
||
|
newIndex = (newIndex + direction + tabValues.Length) % tabValues.Length;
|
||
|
attempts++;
|
||
|
|
||
|
// 상호작용 가능한 탭을 찾았거나 모든 탭을 확인했으면 종료
|
||
|
if (IsTabInteractable(tabValues[newIndex]) || attempts >= maxAttempts)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
} while (newIndex != currentIndex);
|
||
|
|
||
|
// 상호작용 가능한 탭을 찾았으면 이동
|
||
|
if (IsTabInteractable(tabValues[newIndex]))
|
||
|
{
|
||
|
SelectTab(tabValues[newIndex]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 탭 버튼이 상호작용 가능한지 확인합니다.
|
||
|
/// </summary>
|
||
|
public bool IsTabInteractable(int tabValue)
|
||
|
{
|
||
|
if (_tabLookup == null) return false;
|
||
|
return _tabLookup.TryGetValue(tabValue, out var tabButton) && tabButton.IsInteractable == true;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 첫 번째 상호작용 가능한 탭 버튼을 반환합니다.
|
||
|
/// </summary>
|
||
|
public GameObject GetFirstInteractableButton()
|
||
|
{
|
||
|
if (_tabButtons == null || _tabButtons.Count == 0) return null;
|
||
|
|
||
|
foreach (var tabButton in _tabButtons)
|
||
|
{
|
||
|
if (tabButton != null && tabButton.IsInteractable == true)
|
||
|
{
|
||
|
return tabButton.gameObject;
|
||
|
}
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
}
|