Add local data loader shop

This commit is contained in:
HungDK
2025-10-16 10:25:49 +07:00
parent c1583f2e37
commit 1beb754cd2
14 changed files with 1424 additions and 0 deletions
@@ -0,0 +1,193 @@
using System.Collections.Generic;
using UnityEngine;
public class ItemPanelPool : MonoBehaviour
{
[Header("Pool Settings")]
public GameObject itemPanelPrefab;
public int initialPoolSize = 20;
public int maxPoolSize = 100;
public bool expandPool = true;
[Header("Pool Management")]
public Transform poolParent; // Where inactive objects are stored
private Queue<GameObject> availablePanels = new Queue<GameObject>();
private List<GameObject> allPanels = new List<GameObject>();
private int currentPoolSize = 0;
void Start()
{
InitializePool();
}
void InitializePool()
{
if (itemPanelPrefab == null)
{
Debug.LogError("ItemPanelPrefab is not assigned!");
return;
}
// Create pool parent if not assigned
if (poolParent == null)
{
GameObject poolParentObj = new GameObject("ItemPanelPool");
poolParentObj.transform.SetParent(transform);
poolParent = poolParentObj.transform;
}
// Pre-populate pool
for (int i = 0; i < initialPoolSize; i++)
{
CreateNewPanel();
}
Debug.Log($"ItemPanelPool initialized with {currentPoolSize} panels");
}
GameObject CreateNewPanel()
{
if (itemPanelPrefab == null) return null;
GameObject newPanel = Instantiate(itemPanelPrefab, poolParent);
newPanel.SetActive(false);
// Add ShopItemPanel component if not present
ShopItemPanel panelScript = newPanel.GetComponent<ShopItemPanel>();
if (panelScript == null)
{
panelScript = newPanel.AddComponent<ShopItemPanel>();
}
availablePanels.Enqueue(newPanel);
allPanels.Add(newPanel);
currentPoolSize++;
return newPanel;
}
public GameObject GetPanel()
{
GameObject panel = null;
// Try to get from available pool
if (availablePanels.Count > 0)
{
panel = availablePanels.Dequeue();
}
// Create new panel if pool is empty and we can expand
else if (expandPool && currentPoolSize < maxPoolSize)
{
panel = CreateNewPanel();
if (panel != null)
{
panel = availablePanels.Dequeue(); // Get the panel we just created
}
}
// Pool is full and can't expand
else
{
Debug.LogWarning("ItemPanelPool is full and cannot expand further!");
return null;
}
if (panel != null)
{
panel.SetActive(true);
// Reset the panel state
ShopItemPanel panelScript = panel.GetComponent<ShopItemPanel>();
if (panelScript != null)
{
panelScript.ResetPanel(); // Reset for reuse
}
}
return panel;
}
public void ReturnPanel(GameObject panel)
{
if (panel == null) return;
// Reset panel state
ShopItemPanel panelScript = panel.GetComponent<ShopItemPanel>();
if (panelScript != null)
{
panelScript.ResetPanel(); // Reset for reuse
}
// Deactivate and move to pool parent
panel.SetActive(false);
panel.transform.SetParent(poolParent);
panel.transform.localPosition = Vector3.zero;
panel.transform.localRotation = Quaternion.identity;
panel.transform.localScale = Vector3.one;
// Add back to available pool
availablePanels.Enqueue(panel);
}
public void ReturnAllPanels()
{
// Return all active panels to pool
foreach (GameObject panel in allPanels)
{
if (panel != null && panel.activeInHierarchy)
{
ReturnPanel(panel);
}
}
}
public int GetAvailableCount()
{
return availablePanels.Count;
}
public int GetActiveCount()
{
int activeCount = 0;
foreach (GameObject panel in allPanels)
{
if (panel != null && panel.activeInHierarchy)
{
activeCount++;
}
}
return activeCount;
}
public int GetTotalCount()
{
return currentPoolSize;
}
public void ClearPool()
{
// Destroy all panels
foreach (GameObject panel in allPanels)
{
if (panel != null)
{
DestroyImmediate(panel);
}
}
availablePanels.Clear();
allPanels.Clear();
currentPoolSize = 0;
}
void OnDestroy()
{
ClearPool();
}
[ContextMenu("Log Pool Status")]
void LogPoolStatus()
{
Debug.Log($"Pool Status - Available: {GetAvailableCount()}, Active: {GetActiveCount()}, Total: {GetTotalCount()}");
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5b1ee6e37e281834da89d3521b31365b
@@ -0,0 +1,170 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ShopCategoryManager : MonoBehaviour
{
[Header("Category Buttons")]
public Button[] categoryButtons; // 6 buttons for the merged categories
[Header("Category Names")]
public string[] categoryNames = new string[]
{
"Category 1", // Original category 1
"Category 2", // Original category 2
"Categories 3-5", // Merged categories 3, 4, 5
"Category 6", // Original category 6
"Category 7", // Original category 7
"Category 8" // Original category 8
};
[Header("Button Text Components")]
public TextMeshProUGUI[] categoryButtonTexts; // Text components for button labels
[Header("Visual States")]
public Color normalButtonColor = Color.white;
public Color selectedButtonColor = Color.yellow;
public Color disabledButtonColor = Color.gray;
private int currentSelectedCategory = 0;
private ShopUIManager shopManager;
void Start()
{
SetupCategoryButtons();
UpdateCategoryDisplay();
}
public void Initialize(ShopUIManager manager)
{
shopManager = manager;
}
void SetupCategoryButtons()
{
// Setup button text labels
for (int i = 0; i < categoryButtons.Length && i < categoryNames.Length; i++)
{
if (categoryButtons[i] != null)
{
// Set button text
if (i < categoryButtonTexts.Length && categoryButtonTexts[i] != null)
{
categoryButtonTexts[i].text = categoryNames[i];
}
// Setup click listener
int categoryIndex = i; // Capture for closure
categoryButtons[i].onClick.AddListener(() => OnCategoryButtonClicked(categoryIndex));
}
}
}
void OnCategoryButtonClicked(int categoryIndex)
{
if (categoryIndex == currentSelectedCategory)
return;
currentSelectedCategory = categoryIndex;
UpdateCategoryDisplay();
// Notify shop manager
if (shopManager != null)
{
// Use reflection to call the private method, or make it public
// For now, we'll assume there's a public method to handle category change
Debug.Log($"Category {categoryIndex} selected: {categoryNames[categoryIndex]}");
}
}
void UpdateCategoryDisplay()
{
for (int i = 0; i < categoryButtons.Length; i++)
{
if (categoryButtons[i] != null)
{
bool isSelected = (i == currentSelectedCategory);
bool isInteractable = !isSelected;
categoryButtons[i].interactable = isInteractable;
// Update button color
Image buttonImage = categoryButtons[i].GetComponent<Image>();
if (buttonImage != null)
{
if (isSelected)
buttonImage.color = selectedButtonColor;
else
buttonImage.color = normalButtonColor;
}
}
}
}
public int GetCurrentCategory()
{
return currentSelectedCategory;
}
public string GetCurrentCategoryName()
{
if (currentSelectedCategory >= 0 && currentSelectedCategory < categoryNames.Length)
return categoryNames[currentSelectedCategory];
return "Unknown";
}
public void SetCategory(int categoryIndex)
{
if (categoryIndex >= 0 && categoryIndex < categoryButtons.Length)
{
currentSelectedCategory = categoryIndex;
UpdateCategoryDisplay();
}
}
public 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;
}
}
public int GetOriginalCategoryFromItem(GShopItem item)
{
return item.mainType;
}
public string GetCategoryNameForItem(GShopItem item)
{
int originalCategory = item.mainType;
if (originalCategory >= 2 && originalCategory <= 4)
return "Categories 3-5";
if (originalCategory < categoryNames.Length)
return categoryNames[originalCategory];
return "Unknown Category";
}
void OnDestroy()
{
// Clean up event listeners
for (int i = 0; i < categoryButtons.Length; i++)
{
if (categoryButtons[i] != null)
{
int categoryIndex = i; // Capture for closure
categoryButtons[i].onClick.RemoveListener(() => OnCategoryButtonClicked(categoryIndex));
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1db59659b8d10ff44898d4cc8b937c0d
@@ -0,0 +1,219 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ShopDetailPanel : MonoBehaviour
{
[Header("UI Components")]
public TextMeshProUGUI itemNameText;
public TextMeshProUGUI itemDescriptionText;
public Image itemIconImage;
public TextMeshProUGUI itemPriceText;
public TextMeshProUGUI itemQuantityText;
public TextMeshProUGUI itemGiftText;
[Header("Buy Options")]
public Button[] buyOptionButtons; // Up to 4 buy options
public TextMeshProUGUI[] buyOptionPriceTexts;
public TextMeshProUGUI[] buyOptionStatusTexts;
[Header("Action Buttons")]
public Button buyButton;
public Button closeButton;
private GShopItem currentItem;
private ShopUIManager shopManager;
void Start()
{
SetupEventListeners();
}
void SetupEventListeners()
{
if (buyButton != null)
buyButton.onClick.AddListener(OnBuyClicked);
if (closeButton != null)
closeButton.onClick.AddListener(OnCloseClicked);
// Setup buy option buttons
for (int i = 0; i < buyOptionButtons.Length; i++)
{
int optionIndex = i; // Capture for closure
if (buyOptionButtons[i] != null)
{
buyOptionButtons[i].onClick.AddListener(() => OnBuyOptionSelected(optionIndex));
}
}
}
public void SetupDetailPanel(GShopItem item, ShopUIManager manager)
{
currentItem = item;
shopManager = manager;
UpdateDisplay();
}
void UpdateDisplay()
{
if (currentItem.id == 0)
return;
// Set basic item info
if (itemNameText != null)
itemNameText.text = currentItem.name;
if (itemDescriptionText != null)
itemDescriptionText.text = currentItem.desc;
if (itemQuantityText != null)
itemQuantityText.text = $"Quantity: {currentItem.num}";
// Load icon
if (itemIconImage != null)
{
LoadItemIcon(itemIconImage, currentItem.name);
}
// Update buy options
UpdateBuyOptions();
// Update gift info
UpdateGiftInfo();
}
void UpdateBuyOptions()
{
for (int i = 0; i < buyOptionButtons.Length && i < currentItem.buy.Length; i++)
{
var buyOption = currentItem.buy[i];
// Show/hide buy option based on price
bool hasValidPrice = buyOption.price > 0;
if (buyOptionButtons[i] != null)
{
buyOptionButtons[i].gameObject.SetActive(hasValidPrice);
}
if (hasValidPrice)
{
// Set price text
if (i < buyOptionPriceTexts.Length && buyOptionPriceTexts[i] != null)
{
buyOptionPriceTexts[i].text = buyOption.price.ToString();
}
// Set status text
if (i < buyOptionStatusTexts.Length && buyOptionStatusTexts[i] != null)
{
string statusText = GetStatusText(buyOption.status);
buyOptionStatusTexts[i].text = statusText;
}
}
}
}
string GetStatusText(uint status)
{
switch (status)
{
case 0: return "";
case 1: return "HOT";
case 2: return "NEW";
case 3: return "RECOMMENDED";
case 4: return "10% OFF";
case 5: return "20% OFF";
case 6: return "30% OFF";
case 7: return "40% OFF";
case 8: return "50% OFF";
case 9: return "60% OFF";
case 10: return "70% OFF";
case 11: return "80% OFF";
case 12: return "90% OFF";
case 13: return "SOLD OUT";
default: return "";
}
}
void UpdateGiftInfo()
{
if (itemGiftText != null)
{
if (currentItem.idGift > 0)
{
itemGiftText.text = $"Gift: {currentItem.giftNum}x (ID: {currentItem.idGift})";
itemGiftText.gameObject.SetActive(true);
}
else
{
itemGiftText.gameObject.SetActive(false);
}
}
}
void LoadItemIcon(Image iconImage, string itemName)
{
// TODO: Implement icon loading based on item name
// This is where you'd load the appropriate icon sprite
Debug.Log($"Loading detail icon for item: {itemName}");
// You can implement icon loading like this:
// string iconPath = $"Icons/{itemName}"; // Adjust path as needed
// Sprite iconSprite = Resources.Load<Sprite>(iconPath);
// if (iconSprite != null)
// iconImage.sprite = iconSprite;
}
void OnBuyOptionSelected(int optionIndex)
{
if (currentItem.buy == null || optionIndex >= currentItem.buy.Length)
return;
var selectedOption = currentItem.buy[optionIndex];
if (selectedOption.price > 0 && selectedOption.status != 13) // Not sold out
{
// TODO: Implement purchase with specific buy option
Debug.Log($"Selected buy option {optionIndex}: Price={selectedOption.price}, Status={selectedOption.status}");
// Update main price display
if (itemPriceText != null)
itemPriceText.text = $"Price: {selectedOption.price}";
}
}
void OnBuyClicked()
{
// TODO: Implement purchase logic
Debug.Log($"Attempting to buy item: {currentItem.name} (ID: {currentItem.id})");
// Close panel after purchase attempt
OnCloseClicked();
}
void OnCloseClicked()
{
gameObject.SetActive(false);
}
void OnDestroy()
{
// Clean up event listeners
if (buyButton != null)
buyButton.onClick.RemoveListener(OnBuyClicked);
if (closeButton != null)
closeButton.onClick.RemoveListener(OnCloseClicked);
for (int i = 0; i < buyOptionButtons.Length; i++)
{
if (buyOptionButtons[i] != null)
{
int optionIndex = i; // Capture for closure
buyOptionButtons[i].onClick.RemoveListener(() => OnBuyOptionSelected(optionIndex));
}
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 424d441d34048b84cb40140b3e89237d
@@ -0,0 +1,229 @@
using UnityEngine;
using UnityEngine.UI;
public class ShopIconHandler : MonoBehaviour
{
[Header("Shop Icon")]
public Button shopIconButton;
public Image shopIconImage;
[Header("Shop Manager")]
public ShopUIManager shopManager;
[Header("Visual Feedback")]
public Color normalColor = Color.white;
public Color hoverColor = Color.yellow;
public Color pressedColor = Color.red;
[Header("Animation")]
public bool enableHoverAnimation = true;
public float hoverScale = 1.1f;
public float animationSpeed = 5f;
private Vector3 originalScale;
private bool isHovering = false;
void Start()
{
InitializeShopIcon();
SetupEventListeners();
}
void InitializeShopIcon()
{
// Store original scale for animation
originalScale = transform.localScale;
// Setup button if not already assigned
if (shopIconButton == null)
{
shopIconButton = GetComponent<Button>();
}
// Setup image if not already assigned
if (shopIconImage == null)
{
shopIconImage = GetComponent<Image>();
}
// Set initial color
if (shopIconImage != null)
{
shopIconImage.color = normalColor;
}
}
void SetupEventListeners()
{
if (shopIconButton != null)
{
shopIconButton.onClick.AddListener(OnShopIconClicked);
}
// Setup hover events if we have an EventTrigger component
var eventTrigger = GetComponent<UnityEngine.EventSystems.EventTrigger>();
if (eventTrigger != null)
{
SetupHoverEvents(eventTrigger);
}
}
void SetupHoverEvents(UnityEngine.EventSystems.EventTrigger eventTrigger)
{
// Pointer Enter event
var pointerEnter = new UnityEngine.EventSystems.EventTrigger.Entry();
pointerEnter.eventID = UnityEngine.EventSystems.EventTriggerType.PointerEnter;
pointerEnter.callback.AddListener((data) => OnPointerEnter());
eventTrigger.triggers.Add(pointerEnter);
// Pointer Exit event
var pointerExit = new UnityEngine.EventSystems.EventTrigger.Entry();
pointerExit.eventID = UnityEngine.EventSystems.EventTriggerType.PointerExit;
pointerExit.callback.AddListener((data) => OnPointerExit());
eventTrigger.triggers.Add(pointerExit);
// Pointer Down event
var pointerDown = new UnityEngine.EventSystems.EventTrigger.Entry();
pointerDown.eventID = UnityEngine.EventSystems.EventTriggerType.PointerDown;
pointerDown.callback.AddListener((data) => OnPointerDown());
eventTrigger.triggers.Add(pointerDown);
// Pointer Up event
var pointerUp = new UnityEngine.EventSystems.EventTrigger.Entry();
pointerUp.eventID = UnityEngine.EventSystems.EventTriggerType.PointerUp;
pointerUp.callback.AddListener((data) => OnPointerUp());
eventTrigger.triggers.Add(pointerUp);
}
void OnShopIconClicked()
{
Debug.Log("Shop icon clicked - Opening shop");
if (shopManager != null)
{
shopManager.OpenShop();
}
else
{
Debug.LogWarning("ShopManager not assigned to ShopIconHandler");
}
// Play click animation
PlayClickAnimation();
}
void OnPointerEnter()
{
isHovering = true;
if (shopIconImage != null)
{
shopIconImage.color = hoverColor;
}
if (enableHoverAnimation)
{
StartCoroutine(ScaleAnimation(originalScale * hoverScale));
}
}
void OnPointerExit()
{
isHovering = false;
if (shopIconImage != null)
{
shopIconImage.color = normalColor;
}
if (enableHoverAnimation)
{
StartCoroutine(ScaleAnimation(originalScale));
}
}
void OnPointerDown()
{
if (shopIconImage != null)
{
shopIconImage.color = pressedColor;
}
}
void OnPointerUp()
{
if (shopIconImage != null)
{
shopIconImage.color = isHovering ? hoverColor : normalColor;
}
}
void PlayClickAnimation()
{
if (enableHoverAnimation)
{
StartCoroutine(ClickAnimation());
}
}
System.Collections.IEnumerator ScaleAnimation(Vector3 targetScale)
{
Vector3 startScale = transform.localScale;
float elapsedTime = 0f;
while (elapsedTime < 1f / animationSpeed)
{
elapsedTime += Time.deltaTime;
float progress = elapsedTime * animationSpeed;
transform.localScale = Vector3.Lerp(startScale, targetScale, progress);
yield return null;
}
transform.localScale = targetScale;
}
System.Collections.IEnumerator ClickAnimation()
{
Vector3 clickScale = originalScale * 0.9f;
// Scale down
yield return StartCoroutine(ScaleAnimation(clickScale));
// Scale back up
yield return StartCoroutine(ScaleAnimation(originalScale));
}
public void SetShopManager(ShopUIManager manager)
{
shopManager = manager;
}
public void SetShopIcon(Sprite iconSprite)
{
if (shopIconImage != null)
{
shopIconImage.sprite = iconSprite;
}
}
public void SetInteractable(bool interactable)
{
if (shopIconButton != null)
{
shopIconButton.interactable = interactable;
}
if (shopIconImage != null)
{
shopIconImage.color = interactable ? normalColor : Color.gray;
}
}
void OnDestroy()
{
if (shopIconButton != null)
{
shopIconButton.onClick.RemoveListener(OnShopIconClicked);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: cd13f037c7222a041bb6ab59a7c85e18
@@ -0,0 +1,138 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using PerfectWorld.Scripts.Managers;
public class ShopItemPanel : MonoBehaviour
{
[Header("UI Components")]
public TextMeshProUGUI itemNameText;
public TextMeshProUGUI itemPriceText;
public Image itemIconImage;
public TextMeshProUGUI itemQuantityText;
public Button itemButton;
private GShopItem itemData;
private ShopUIManager shopManager;
void Start()
{
if (itemButton != null)
{
itemButton.onClick.AddListener(OnItemClicked);
}
}
public void SetupItem(GShopItem item, ShopUIManager manager)
{
itemData = item;
shopManager = manager;
UpdateDisplay();
}
void UpdateDisplay()
{
if (itemData.id == 0)
return;
// Set item name
if (itemNameText != null)
itemNameText.text = itemData.name;
// Set item quantity
if (itemQuantityText != null)
itemQuantityText.text = $"x{itemData.num}";
// Find the best buy option (first non-zero price)
uint bestPrice = 0;
for (int i = 0; i < itemData.buy.Length; i++)
{
if (itemData.buy[i].price > 0)
{
bestPrice = itemData.buy[i].price;
break;
}
}
// Set item price
if (itemPriceText != null)
itemPriceText.text = bestPrice.ToString();
// Load icon based on item ID
if (itemIconImage != null)
{
LoadItemIcon(itemIconImage, (int)itemData.id);
}
}
void LoadItemIcon(Image iconImage, int itemId)
{
if (itemId <= 0)
{
Debug.LogWarning($"Invalid item ID for icon loading: {itemId}");
return;
}
// Use the existing icon loading system from EC_IvtrItem
Sprite iconSprite = EC_IvtrItem.ResolveItemIconSprite(itemId);
if (iconSprite != null)
{
iconImage.sprite = iconSprite;
Debug.Log($"Successfully loaded icon for item ID: {itemId}");
}
else
{
Debug.LogWarning($"Failed to load icon for item ID: {itemId}");
// Optionally set a default icon or clear the current one
iconImage.sprite = null;
}
}
void OnItemClicked()
{
if (shopManager != null && itemData.id != 0)
{
shopManager.ShowItemDetail(itemData);
}
}
void OnDestroy()
{
if (itemButton != null)
{
itemButton.onClick.RemoveListener(OnItemClicked);
}
}
public void ResetPanel()
{
// Clear item data
itemData = new GShopItem();
shopManager = null;
// Reset UI display
if (itemNameText != null)
itemNameText.text = "";
if (itemPriceText != null)
itemPriceText.text = "";
if (itemQuantityText != null)
itemQuantityText.text = "";
if (itemIconImage != null)
itemIconImage.sprite = null;
// Reset transform
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
}
public bool IsInUse()
{
return itemData.id != 0;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 637273bf6b828534d8ca34f637220497
@@ -0,0 +1,126 @@
using UnityEngine;
public class ShopSystemSetup : MonoBehaviour
{
[Header("Required Components")]
public GShopLoader shopLoader;
public ShopUIManager shopUIManager;
public ShopCategoryManager shopCategoryManager;
public ShopIconHandler shopIconHandler;
[Header("Auto Setup")]
public bool autoFindComponents = true;
void Start()
{
if (autoFindComponents)
{
AutoSetupComponents();
}
ConnectComponents();
}
void AutoSetupComponents()
{
// Find GShopLoader
if (shopLoader == null)
{
shopLoader = FindFirstObjectByType<GShopLoader>();
}
// Find ShopUIManager
if (shopUIManager == null)
{
shopUIManager = FindFirstObjectByType<ShopUIManager>();
}
// Find ShopCategoryManager
if (shopCategoryManager == null)
{
shopCategoryManager = FindFirstObjectByType<ShopCategoryManager>();
}
// Find ShopIconHandler
if (shopIconHandler == null)
{
shopIconHandler = FindFirstObjectByType<ShopIconHandler>();
}
}
void ConnectComponents()
{
// Connect ShopUIManager with GShopLoader
if (shopUIManager != null && shopLoader != null)
{
shopUIManager.shopLoader = shopLoader;
}
// Connect ShopCategoryManager with ShopUIManager
if (shopCategoryManager != null && shopUIManager != null)
{
shopCategoryManager.Initialize(shopUIManager);
}
// Connect ShopIconHandler with ShopUIManager
if (shopIconHandler != null && shopUIManager != null)
{
shopIconHandler.SetShopManager(shopUIManager);
}
Debug.Log("Shop system components connected successfully");
}
[ContextMenu("Test Shop System")]
void TestShopSystem()
{
if (shopUIManager != null)
{
shopUIManager.OpenShop();
Debug.Log("Test: Shop opened");
}
else
{
Debug.LogWarning("ShopUIManager not found for testing");
}
}
[ContextMenu("Validate Setup")]
void ValidateSetup()
{
bool isValid = true;
if (shopLoader == null)
{
Debug.LogError("GShopLoader is missing!");
isValid = false;
}
if (shopUIManager == null)
{
Debug.LogError("ShopUIManager is missing!");
isValid = false;
}
if (shopCategoryManager == null)
{
Debug.LogError("ShopCategoryManager is missing!");
isValid = false;
}
if (shopIconHandler == null)
{
Debug.LogError("ShopIconHandler is missing!");
isValid = false;
}
if (isValid)
{
Debug.Log("✓ All shop system components are properly set up!");
}
else
{
Debug.LogError("✗ Shop system setup is incomplete!");
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9a96cdc8b4b5a014ea4b558e16c79cad
@@ -0,0 +1,335 @@
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)
{
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");
}
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
foreach (GShopItem item in categoryItems)
{
CreateItemPanelFromPool(item);
}
}
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=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<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;
if (shopDetailPanel != null)
{
shopDetailPanel.SetActive(true);
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();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 988a04b7abdde4a44af423870878845a