using System.Collections.Generic; using UnityEngine; using Colosseum.Abnormalities; namespace Colosseum.UI { /// /// 이상 상태 목록 UI 관리자 /// 버프/디버프 목록을 표시하고 관리합니다. /// public class AbnormalityListUI : MonoBehaviour { [Header("Containers")] [Tooltip("버프 컨테이너")] [SerializeField] private Transform buffContainer; [Tooltip("디버프 컨테이너")] [SerializeField] private Transform debuffContainer; [Header("Prefab")] [Tooltip("이상 상태 슬롯 프리팹")] [SerializeField] private AbnormalitySlotUI slotPrefab; [Header("Settings")] [Tooltip("최대 표시 개수")] [SerializeField] private int maxSlots = 10; [Tooltip("자동으로 플레이어 추적")] [SerializeField] private bool autoFindPlayer = true; // 추적 중인 AbnormalityManager private AbnormalityManager targetManager; // 생성된 슬롯 풀 private readonly List slotPool = new List(); // 현재 활성화된 슬롯 목록 private readonly List activeSlots = new List(); // 이전 프레임의 효과 수 (변경 감지용) private int lastAbnormalityCount = -1; private void Start() { if (autoFindPlayer) { // 로컬 플레이어 찾기 FindLocalPlayer(); } // 슬롯 풀 초기화 InitializeSlotPool(); } private void OnDestroy() { // 이벤트 구독 해제 if (targetManager != null) { targetManager.OnAbnormalityAdded -= OnAbnormalityAdded; targetManager.OnAbnormalityRemoved -= OnAbnormalityRemoved; targetManager.OnAbnormalitiesChanged -= OnAbnormalitiesChanged; } } private void Update() { // 주기적으로 UI 갱신 (성능 최적화를 위해 매 프레임이 아닌 일정 간격으로) if (Time.frameCount % 10 == 0) // 10프레임마다 한 번 { RefreshUI(); } } /// /// 로컬 플레이어 찾기 /// private void FindLocalPlayer() { var playerObjects = FindObjectsByType(FindObjectsSortMode.None); foreach (var manager in playerObjects) { // 네트워크 오브젝트인 경우 로컬 플레이어 확인 if (manager.TryGetComponent(out var netObj) && netObj.IsOwner) { SetTarget(manager); return; } } // 네트워크 오브젝트가 없거나 로컬 플레이어를 찾지 못한 경우 // 첫 번째 플레이어 사용 (싱글플레이어용) if (playerObjects.Length > 0) { SetTarget(playerObjects[0]); } } /// /// 추적 대상 설정 /// /// 추적할 AbnormalityManager public void SetTarget(AbnormalityManager manager) { // 기존 구독 해제 if (targetManager != null) { targetManager.OnAbnormalityAdded -= OnAbnormalityAdded; targetManager.OnAbnormalityRemoved -= OnAbnormalityRemoved; targetManager.OnAbnormalitiesChanged -= OnAbnormalitiesChanged; } targetManager = manager; // 새로운 대상 구독 if (targetManager != null) { targetManager.OnAbnormalityAdded += OnAbnormalityAdded; targetManager.OnAbnormalityRemoved += OnAbnormalityRemoved; targetManager.OnAbnormalitiesChanged += OnAbnormalitiesChanged; } // 즉시 UI 갱신 ForceRefreshUI(); } /// /// 슬롯 풀 초기화 /// private void InitializeSlotPool() { if (slotPrefab == null) { Debug.LogWarning("[AbnormalityListUI] Slot prefab is not assigned"); return; } // 필요한 만큼 슬롯 미리 생성 for (int i = 0; i < maxSlots; i++) { var slot = CreateSlot(); slot.gameObject.SetActive(false); slotPool.Add(slot); } } /// /// 새 슬롯 생성 /// private AbnormalitySlotUI CreateSlot() { var go = Instantiate(slotPrefab.gameObject, transform); return go.GetComponent(); } /// /// 슬롯 가져오기 (풀에서 또는 새로 생성) /// private AbnormalitySlotUI GetSlot() { // 풀에서 비활성화된 슬롯 찾기 foreach (var slot in slotPool) { if (!slot.gameObject.activeSelf) { return slot; } } // 풀에 없으면 새로 생성 if (slotPool.Count < maxSlots) { var newSlot = CreateSlot(); slotPool.Add(newSlot); return newSlot; } return null; } /// /// 슬롯 반환 (비활성화) /// private void ReturnSlot(AbnormalitySlotUI slot) { slot.gameObject.SetActive(false); activeSlots.Remove(slot); } /// /// 이상 상태 추가 시 호출 /// private void OnAbnormalityAdded(ActiveAbnormality abnormality) { ForceRefreshUI(); } /// /// 이상 상태 제거 시 호출 /// private void OnAbnormalityRemoved(ActiveAbnormality abnormality) { ForceRefreshUI(); } /// /// 이상 상태 변경 시 호출 /// private void OnAbnormalitiesChanged() { ForceRefreshUI(); } /// /// UI 강제 갱신 /// public void ForceRefreshUI() { if (targetManager == null) return; // 모든 슬롯 반환 foreach (var slot in activeSlots.ToArray()) { ReturnSlot(slot); } activeSlots.Clear(); // 활성화된 이상 상태 표시 var abnormalities = targetManager.ActiveAbnormalities; foreach (var abnormality in abnormalities) { var slot = GetSlot(); if (slot == null) continue; // 버프/디버프에 따라 적절한 컨테이너에 배치 Transform container = abnormality.Data.isDebuff ? debuffContainer : buffContainer; if (container == null) container = transform; slot.transform.SetParent(container, false); slot.Initialize(abnormality); slot.gameObject.SetActive(true); activeSlots.Add(slot); } lastAbnormalityCount = abnormalities.Count; } /// /// UI 주기적 갱신 (변경 감지 시에만) /// private void RefreshUI() { if (targetManager == null) return; int currentCount = targetManager.ActiveAbnormalities.Count; // 이상 상태 수가 변경되었으면 갱신 if (currentCount != lastAbnormalityCount) { ForceRefreshUI(); } } /// /// 모든 슬롯 숨기기 /// public void HideAll() { foreach (var slot in activeSlots.ToArray()) { ReturnSlot(slot); } activeSlots.Clear(); } } }