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() { Debug.Log("[AbnormalityListUI] Start() called"); if (autoFindPlayer) { // 로컬 플레이어 찾기 FindLocalPlayer(); } // 슬롯 풀 초기화 InitializeSlotPool(); Debug.Log($"[AbnormalityListUI] slotPrefab: {(slotPrefab != null ? slotPrefab.name : "NULL")}"); Debug.Log($"[AbnormalityListUI] buffContainer: {(buffContainer != null ? buffContainer.name : "NULL")}"); Debug.Log($"[AbnormalityListUI] debuffContainer: {(debuffContainer != null ? debuffContainer.name : "NULL")}"); } private void OnDestroy() { // 이벤트 구독 해제 if (targetManager != null) { targetManager.OnAbnormalityAdded -= OnAbnormalityAdded; targetManager.OnAbnormalityRemoved -= OnAbnormalityRemoved; targetManager.OnAbnormalitiesChanged -= OnAbnormalitiesChanged; } } private void Update() { // 타겟이 없으면 주기적으로 플레이어 찾기 if (targetManager == null && autoFindPlayer && Time.frameCount % 30 == 0) { FindLocalPlayer(); } // 주기적으로 UI 갱신 (성능 최적화를 위해 매 프레임이 아닌 일정 간격으로) if (Time.frameCount % 10 == 0) // 10프레임마다 한 번 { RefreshUI(); } } /// /// 로컬 플레이어 찾기 /// private void FindLocalPlayer() { var playerObjects = FindObjectsByType(FindObjectsSortMode.None); Debug.Log($"[AbnormalityListUI] Found {playerObjects.Length} AbnormalityManager(s)"); foreach (var manager in playerObjects) { // 네트워크 오브젝트인 경우 로컬 플레이어 확인 if (manager.TryGetComponent(out var netObj)) { Debug.Log($"[AbnormalityListUI] Checking {manager.gameObject.name}, IsOwner: {netObj.IsOwner}"); if (netObj.IsOwner) { Debug.Log($"[AbnormalityListUI] Setting target to local player: {manager.gameObject.name}"); SetTarget(manager); return; } } } // 네트워크 오브젝트가 없거나 로컬 플레이어를 찾지 못한 경우 // 첫 번째 플레이어 사용 (싱글플레이어용) if (playerObjects.Length > 0) { Debug.Log($"[AbnormalityListUI] No local player found, using first manager: {playerObjects[0].gameObject.name}"); SetTarget(playerObjects[0]); } else { Debug.LogWarning("[AbnormalityListUI] No AbnormalityManager found!"); } } /// /// 추적 대상 설정 /// /// 추적할 AbnormalityManager public void SetTarget(AbnormalityManager manager) { Debug.Log($"[AbnormalityListUI] SetTarget called with: {(manager != null ? manager.gameObject.name : "null")}"); // 기존 구독 해제 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; Debug.Log("[AbnormalityListUI] Events subscribed successfully"); } // 즉시 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) { Debug.Log($"[AbnormalityListUI] OnAbnormalityAdded event received: {abnormality.Data.abnormalityName}"); ForceRefreshUI(); } /// /// 이상 상태 제거 시 호출 /// private void OnAbnormalityRemoved(ActiveAbnormality abnormality) { Debug.Log($"[AbnormalityListUI] OnAbnormalityRemoved event received: {abnormality.Data.abnormalityName}"); ForceRefreshUI(); } /// /// 이상 상태 변경 시 호출 /// private void OnAbnormalitiesChanged() { Debug.Log("[AbnormalityListUI] OnAbnormalitiesChanged event received"); ForceRefreshUI(); } /// /// UI 강제 갱신 /// public void ForceRefreshUI() { if (targetManager == null) { Debug.LogWarning("[AbnormalityListUI] ForceRefreshUI called but targetManager is null"); return; } // 모든 슬롯 반환 foreach (var slot in activeSlots.ToArray()) { ReturnSlot(slot); } activeSlots.Clear(); // 활성화된 이상 상태 표시 var abnormalities = targetManager.ActiveAbnormalities; Debug.Log($"[AbnormalityListUI] ForceRefreshUI: {abnormalities.Count} abnormalities found"); foreach (var abnormality in abnormalities) { var slot = GetSlot(); if (slot == null) { Debug.LogWarning("[AbnormalityListUI] Could not get slot from pool"); continue; } // 버프/디버프에 따라 적절한 컨테이너에 배치 Transform container = abnormality.Data.isDebuff ? debuffContainer : buffContainer; if (container == null) container = transform; Debug.Log($"[AbnormalityListUI] Adding slot for: {abnormality.Data.abnormalityName}, isDebuff: {abnormality.Data.isDebuff}, container: {container.name}"); 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(); } // 활성 슬롯들의 지속 시간 업데이트 UpdateSlotDurations(); } /// /// 모든 활성 슬롯의 지속 시간 업데이트 /// private void UpdateSlotDurations() { foreach (var slot in activeSlots) { if (slot != null && slot.TrackedAbnormality != null) { var abnormality = slot.TrackedAbnormality; slot.UpdateDisplay(abnormality.RemainingDuration, abnormality.Data.duration); } } } /// /// 모든 슬롯 숨기기 /// public void HideAll() { foreach (var slot in activeSlots.ToArray()) { ReturnSlot(slot); } activeSlots.Clear(); } } }