using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; public class ShopUIManager : MonoBehaviour { [Header("Shop Data")] public GShopLoader shopLoader; [Header("UI Panels")] public GameObject shopMainPanel; public GameObject shopDetailPanel; [Header("Item Display")] public Transform itemContainer; // Parent for item panels public GameObject itemPanelPrefab; // Prefab for individual item panels [Header("Object Pooling")] public ItemPanelPool itemPanelPool; // Object pool for item panels public bool useObjectPooling = true; [Header("Category Buttons")] public Button[] categoryButtons; // 6 buttons for categories [Header("Detail Panel Components")] public TextMeshProUGUI detailItemName; public TextMeshProUGUI detailItemDescription; public Image detailItemIcon; public TextMeshProUGUI detailItemPrice; public TextMeshProUGUI detailItemQuantity; public Button buyButton; public Button closeDetailButton; [Header("Main Panel Components")] public Button closeShopButton; private List currentItemPanels = new List(); private GShopItem selectedItem; private int currentCategory = 0; // 0-5 for the 6 merged categories void Start() { InitializeUI(); SetupEventListeners(); InitializePool(); } void InitializePool() { if (useObjectPooling && itemPanelPool == null) { // Auto-create pool if not assigned GameObject poolObj = new GameObject("ItemPanelPool"); poolObj.transform.SetParent(transform); itemPanelPool = poolObj.AddComponent(); itemPanelPool.itemPanelPrefab = itemPanelPrefab; } } void InitializeUI() { // Initially hide panels if (shopMainPanel != null) shopMainPanel.SetActive(false); if (shopDetailPanel != null) shopDetailPanel.SetActive(false); } void SetupEventListeners() { // Setup category buttons for (int i = 0; i < categoryButtons.Length && i < 6; i++) { int categoryIndex = i; // Capture for closure categoryButtons[i].onClick.AddListener(() => OnCategorySelected(categoryIndex)); } // Setup detail panel buttons if (buyButton != null) buyButton.onClick.AddListener(OnBuyItem); if (closeDetailButton != null) closeDetailButton.onClick.AddListener(CloseDetailPanel); // Setup main panel close button if (closeShopButton != null) closeShopButton.onClick.AddListener(CloseShop); } public void OpenShop() { if (shopMainPanel != null) { shopMainPanel.SetActive(true); RefreshShopDisplay(); } } public void CloseShop() { if (shopMainPanel != null) shopMainPanel.SetActive(false); if (shopDetailPanel != null) shopDetailPanel.SetActive(false); } void OnCategorySelected(int categoryIndex) { if (categoryIndex == currentCategory) return; float startTime = Time.realtimeSinceStartup; currentCategory = categoryIndex; RefreshShopDisplay(); // Update button states for (int i = 0; i < categoryButtons.Length; i++) { if (categoryButtons[i] != null) { categoryButtons[i].interactable = (i != categoryIndex); } } // Log performance float switchTime = Time.realtimeSinceStartup - startTime; Debug.Log($"Category switch to {categoryIndex} completed in {switchTime * 1000f:F2}ms"); } public void RefreshShopDisplay() { // Return all current panels to pool ReturnAllPanelsToPool(); if (shopLoader == null || shopLoader.primaryShop == null) { Debug.LogWarning("ShopLoader or primary shop data not available"); return; } // Get items for current category List categoryItems = GetItemsForCategory(currentCategory); // Create item panels using pooling foreach (GShopItem item in categoryItems) { CreateItemPanelFromPool(item); } } List GetItemsForCategory(int categoryIndex) { List items = new List(); if (shopLoader.primaryShop.items == null) return items; foreach (GShopItem item in shopLoader.primaryShop.items) { if (IsItemInCategory(item, categoryIndex)) { items.Add(item); } } return items; } bool IsItemInCategory(GShopItem item, int categoryIndex) { // Category mapping: 0=1, 1=2, 2=3+4+5, 3=6, 4=7, 5=8 switch (categoryIndex) { case 0: return item.mainType == 0; // Category 1 case 1: return item.mainType == 1; // Category 2 case 2: return item.mainType >= 2 && item.mainType <= 4; // Categories 3, 4, 5 merged case 3: return item.mainType == 5; // Category 6 case 4: return item.mainType == 6; // Category 7 case 5: return item.mainType == 7; // Category 8 default: return false; } } void CreateItemPanelFromPool(GShopItem item) { GameObject itemPanel = null; if (useObjectPooling && itemPanelPool != null) { // Get panel from pool itemPanel = itemPanelPool.GetPanel(); } else { // Fallback to instantiate if pooling disabled if (itemPanelPrefab != null && itemContainer != null) { itemPanel = Instantiate(itemPanelPrefab, itemContainer); } } if (itemPanel != null && itemContainer != null) { // Set parent and position itemPanel.transform.SetParent(itemContainer); itemPanel.transform.localScale = Vector3.one; // Setup the panel ShopItemPanel itemPanelScript = itemPanel.GetComponent(); if (itemPanelScript != null) { itemPanelScript.SetupItem(item, this); } currentItemPanels.Add(itemPanel); } } void ReturnAllPanelsToPool() { if (useObjectPooling && itemPanelPool != null) { // Return all panels to pool foreach (GameObject panel in currentItemPanels) { if (panel != null) { itemPanelPool.ReturnPanel(panel); } } } else { // Destroy panels if not using pooling foreach (GameObject panel in currentItemPanels) { if (panel != null) Destroy(panel); } } currentItemPanels.Clear(); } public void ShowItemDetail(GShopItem item) { selectedItem = item; Debug.Log($"$ Local ID of selected item: {item.localId}"); if (shopDetailPanel != null) { shopDetailPanel.SetActive(true); // Get the ShopDetailPanel component and call its SetupDetailPanel method ShopDetailPanel detailPanelScript = shopDetailPanel.GetComponent(); if (detailPanelScript != null) { detailPanelScript.SetupDetailPanel(item, this); } else { Debug.LogError("ShopDetailPanel script not found on shopDetailPanel GameObject!"); // Fallback to the old method UpdateDetailPanel(item); } } } void UpdateDetailPanel(GShopItem item) { if (detailItemName != null) detailItemName.text = item.name; if (detailItemDescription != null) detailItemDescription.text = item.desc; if (detailItemQuantity != null) detailItemQuantity.text = $"Quantity: {item.num}"; // Find the best buy option (first non-zero price) uint bestPrice = 0; for (int i = 0; i < item.buy.Length; i++) { if (item.buy[i].price > 0) { bestPrice = item.buy[i].price; break; } } if (detailItemPrice != null) detailItemPrice.text = $"Price: {bestPrice}"; // Load icon based on item name (you'll need to implement icon loading) if (detailItemIcon != null) { LoadItemIcon(detailItemIcon, item.name); } } void LoadItemIcon(Image iconImage, string itemName) { // TODO: Implement icon loading based on item name // This is where you'd load the appropriate icon sprite // For now, we'll leave it empty for you to implement Debug.Log($"Loading icon for item: {itemName}"); } void CloseDetailPanel() { if (shopDetailPanel != null) shopDetailPanel.SetActive(false); } void OnBuyItem() { if (selectedItem.id == 0) return; // TODO: Implement purchase logic Debug.Log($"Attempting to buy item: {selectedItem.name} (ID: {selectedItem.id})"); // Close detail panel after purchase attempt CloseDetailPanel(); } void OnDestroy() { // Clean up pooled objects if (useObjectPooling && itemPanelPool != null) { itemPanelPool.ReturnAllPanels(); } else { // Fallback cleanup foreach (GameObject panel in currentItemPanels) { if (panel != null) Destroy(panel); } } currentItemPanels.Clear(); } }