Files
test/Assets/PerfectWorld/Scripts/UI/ShopUIManager.cs
T
2025-11-10 16:13:31 +07:00

358 lines
11 KiB
C#

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<GameObject> currentItemPanels = new List<GameObject>();
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>();
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)
{
OnCategorySelected(0);
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");
}
// Allow external components (e.g., ShopCategoryManager) to switch category
public void SetCategoryIndex(int categoryIndex)
{
OnCategorySelected(categoryIndex);
}
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<GShopItem> categoryItems = GetItemsForCategory(currentCategory);
// Create item panels using pooling
int siblingIndexCounter = 0;
foreach (GShopItem item in categoryItems)
{
CreateItemPanelFromPool(item, siblingIndexCounter);
siblingIndexCounter++;
}
}
List<GShopItem> GetItemsForCategory(int categoryIndex)
{
List<GShopItem> items = new List<GShopItem>();
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=1+3+4, 3=6, 4=7, 5=8
switch (categoryIndex)
{
case 0: return item.mainType == 0; // Category 1
case 1: return item.mainType == 2; // Category 2
case 2: return item.mainType == 5; // Categories 1, 3, 4 merged
case 3: return item.mainType == 1 || item.mainType == 3 || item.mainType == 4; // 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, int targetSiblingIndex)
{
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, false);
itemPanel.transform.localScale = Vector3.one;
// Ensure deterministic ordering regardless of pool retrieval order
itemPanel.transform.SetSiblingIndex(targetSiblingIndex);
// Setup the panel
ShopItemPanel itemPanelScript = itemPanel.GetComponent<ShopItemPanel>();
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<ShopDetailPanel>();
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();
}
}