Add Shop system with ShopManager, ShopUI, and ShopSlotUI; implement item purchasing and shop UI functionality
This commit is contained in:
96
Assets/Scripts/Shop/ShopManager.cs
Normal file
96
Assets/Scripts/Shop/ShopManager.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Inventory;
|
||||
using Sirenix.Serialization;
|
||||
using Systems;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Shop
|
||||
{
|
||||
public class ShopManager : MonoBehaviour
|
||||
{
|
||||
private List<StatModifierItem> currentItemChoices = new();
|
||||
private List<WeaponItem> currentWeaponChoices = new();
|
||||
|
||||
[SerializeField] private ShopUI shopUI;
|
||||
[SerializeField] private InventoryManager inventoryManager;
|
||||
|
||||
[SerializeField] private int itemsPerShop = 4;
|
||||
[OdinSerialize, SerializeField] private List<StatModifierItem> possibleItems = new();
|
||||
[OdinSerialize, SerializeField] private List<WeaponItem> possibleWeapons = new();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
// GameManager.Instance.OnRoundEnd += OpenShop;
|
||||
GameManager.Instance.OnStoreOpen += OpenShop;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
// GameManager.Instance.OnRoundEnd -= OpenShop;
|
||||
GameManager.Instance.OnStoreOpen -= OpenShop;
|
||||
}
|
||||
|
||||
public void CloseShop()
|
||||
{
|
||||
shopUI.Hide();
|
||||
Time.timeScale = 1f;
|
||||
}
|
||||
|
||||
public void BuyItem(StatModifierItem item, int price)
|
||||
{
|
||||
if (GameManager.Instance.Coins < price) return;
|
||||
|
||||
GameManager.Instance.SpendCoins(price);
|
||||
inventoryManager.EquipItem(item);
|
||||
shopUI.MarkAsPurchased(item);
|
||||
}
|
||||
|
||||
public void BuyWeapon(WeaponItem weapon, int price)
|
||||
{
|
||||
if (GameManager.Instance.Coins < price) return;
|
||||
|
||||
GameManager.Instance.SpendCoins(price);
|
||||
inventoryManager.EquipWeapon(weapon);
|
||||
shopUI.MarkAsPurchased(weapon);
|
||||
}
|
||||
|
||||
public void RerollShop()
|
||||
{
|
||||
currentItemChoices = DrawRandomItems(possibleItems, itemsPerShop);
|
||||
currentWeaponChoices = DrawRandomItems(possibleWeapons, itemsPerShop);
|
||||
|
||||
shopUI.Show(currentItemChoices, currentWeaponChoices, this);
|
||||
}
|
||||
|
||||
private void OpenShop()
|
||||
{
|
||||
OpenShop(GameManager.Instance.CurrentRound);
|
||||
}
|
||||
|
||||
private void OpenShop(int round)
|
||||
{
|
||||
currentItemChoices = DrawRandomItems(possibleItems, itemsPerShop);
|
||||
currentWeaponChoices = DrawRandomItems(possibleWeapons, itemsPerShop);
|
||||
|
||||
shopUI.Show(currentItemChoices, currentWeaponChoices, this);
|
||||
Time.timeScale = 0f;
|
||||
}
|
||||
|
||||
private List<T> DrawRandomItems<T>(List<T> pool, int count)
|
||||
{
|
||||
var result = new List<T>();
|
||||
var poolCopy = new List<T>(pool);
|
||||
|
||||
for (var i = 0; i < count && poolCopy.Count > 0; i++)
|
||||
{
|
||||
var idx = Random.Range(0, poolCopy.Count);
|
||||
result.Add(poolCopy[idx]);
|
||||
poolCopy.RemoveAt(idx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Scripts/Shop/ShopManager.cs.meta
Normal file
3
Assets/Scripts/Shop/ShopManager.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3f37c728615643a1abc988bbfd34986c
|
||||
timeCreated: 1752272671
|
56
Assets/Scripts/Shop/ShopSlotUI.cs
Normal file
56
Assets/Scripts/Shop/ShopSlotUI.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Inventory;
|
||||
using Systems;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Shop
|
||||
{
|
||||
public class ShopSlotUI : MonoBehaviour
|
||||
{
|
||||
private ScriptableObject item;
|
||||
private ShopManager shopManager;
|
||||
private int price;
|
||||
|
||||
[SerializeField] private Image icon;
|
||||
[SerializeField] private TextMeshProUGUI nameText;
|
||||
[SerializeField] private TextMeshProUGUI descriptionText;
|
||||
[SerializeField] private TextMeshProUGUI priceText;
|
||||
[SerializeField] private Button purchaseButton;
|
||||
|
||||
public void Setup(StatModifierItem item, ShopManager manager)
|
||||
{
|
||||
this.item = item;
|
||||
shopManager = manager;
|
||||
price = item.price;
|
||||
|
||||
icon.sprite = item.icon;
|
||||
nameText.text = item.name;
|
||||
descriptionText.text = item.description;
|
||||
priceText.text = $"Price: {price}";
|
||||
|
||||
purchaseButton.interactable = GameManager.Instance.Coins >= price;
|
||||
purchaseButton.onClick.AddListener(() => shopManager.BuyItem(item, price));
|
||||
}
|
||||
|
||||
public void Setup(WeaponItem weapon, ShopManager manager)
|
||||
{
|
||||
item = weapon;
|
||||
shopManager = manager;
|
||||
price = weapon.price;
|
||||
icon.sprite = weapon.icon;
|
||||
nameText.text = weapon.weaponName;
|
||||
descriptionText.text = weapon.description;
|
||||
priceText.text = $"Price: {price}";
|
||||
purchaseButton.interactable = GameManager.Instance.Coins >= price;
|
||||
purchaseButton.onClick.AddListener(() => shopManager.BuyWeapon(weapon, price));
|
||||
}
|
||||
|
||||
public bool MatchesItem(ScriptableObject item) => this.item == item;
|
||||
|
||||
public void MarkAsPurchased()
|
||||
{
|
||||
purchaseButton.interactable = false;
|
||||
}
|
||||
}
|
||||
}
|
3
Assets/Scripts/Shop/ShopSlotUI.cs.meta
Normal file
3
Assets/Scripts/Shop/ShopSlotUI.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d76cc9c15ed441b930dbe52e5e9af5f
|
||||
timeCreated: 1752273703
|
83
Assets/Scripts/Shop/ShopUI.cs
Normal file
83
Assets/Scripts/Shop/ShopUI.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Inventory;
|
||||
using Systems;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Shop
|
||||
{
|
||||
public class ShopUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private GameObject shopPanel;
|
||||
[SerializeField] private Transform itemSlotParent;
|
||||
[SerializeField] private Transform weaponSlotParent;
|
||||
[SerializeField] private ShopSlotUI slotPrefab;
|
||||
[SerializeField] private TextMeshProUGUI roundsText;
|
||||
|
||||
private List<ShopSlotUI> currentSlots = new();
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
GameManager.Instance.OnRoundEnd += UpdateRoundText;
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
GameManager.Instance.OnRoundEnd -= UpdateRoundText;
|
||||
}
|
||||
|
||||
public void Show(List<StatModifierItem> items, List<WeaponItem> weapons, ShopManager shopManager)
|
||||
{
|
||||
GameManager.Instance.StoreIsClosed = false;
|
||||
UpdateRoundText(GameManager.Instance.CurrentRound);
|
||||
|
||||
shopPanel.SetActive(true);
|
||||
ClearSlots();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
var slot = Instantiate(slotPrefab, itemSlotParent);
|
||||
slot.Setup(item, shopManager);
|
||||
currentSlots.Add(slot);
|
||||
}
|
||||
|
||||
foreach (var weapon in weapons)
|
||||
{
|
||||
var slot = Instantiate(slotPrefab, weaponSlotParent);
|
||||
slot.Setup(weapon, shopManager);
|
||||
currentSlots.Add(slot);
|
||||
}
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
GameManager.Instance.StoreIsClosed = true;
|
||||
shopPanel.SetActive(false);
|
||||
ClearSlots();
|
||||
}
|
||||
|
||||
public void MarkAsPurchased(ScriptableObject item)
|
||||
{
|
||||
foreach (var slot in currentSlots)
|
||||
{
|
||||
if (slot.MatchesItem(item)) slot.MarkAsPurchased();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSlots()
|
||||
{
|
||||
foreach (var slot in currentSlots) Destroy(slot.gameObject);
|
||||
|
||||
currentSlots.Clear();
|
||||
}
|
||||
|
||||
private void UpdateRoundText(int round)
|
||||
{
|
||||
var nextRound = Mathf.Min(round + 1, GameManager.Instance.MaxRounds);
|
||||
roundsText.text = $"Round: {nextRound}/{GameManager.Instance.MaxRounds}";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
3
Assets/Scripts/Shop/ShopUI.cs.meta
Normal file
3
Assets/Scripts/Shop/ShopUI.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: abe11e705b4f47feb25a4e4845d1e6e9
|
||||
timeCreated: 1752272723
|
Reference in New Issue
Block a user