fack
This commit is contained in:
286
Assets/Inventory/Scripts/Slot.cs
Normal file
286
Assets/Inventory/Scripts/Slot.cs
Normal file
@@ -0,0 +1,286 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
/// <summary>
|
||||
/// Слот инвентаря - отображает предмет и его количество
|
||||
/// </summary>
|
||||
public class Slot : MonoBehaviour
|
||||
{
|
||||
public int slotIndex;
|
||||
public ItemData item;
|
||||
public int amount;
|
||||
|
||||
[Header("UI References")]
|
||||
public Image iconImage;
|
||||
public TextMeshProUGUI amountText;
|
||||
public GameObject amountPanel;
|
||||
public Image slotBackground;
|
||||
|
||||
[Header("Visual Settings")]
|
||||
[SerializeField] private Color emptySlotColor = new Color(0.2f, 0.2f, 0.2f, 0.5f);
|
||||
[SerializeField] private Color filledSlotColor = new Color(0.3f, 0.3f, 0.3f, 0.9f);
|
||||
[SerializeField] private Color hoverColor = new Color(0.5f, 0.5f, 0.5f, 1f);
|
||||
[SerializeField] private Color selectedColor = new Color(0.4f, 0.6f, 0.9f, 1f);
|
||||
|
||||
[Header("Drag & Drop")]
|
||||
[SerializeField] private bool allowDrag = true;
|
||||
|
||||
public bool IsEmpty => item == null || amount <= 0;
|
||||
public bool HasItem => !IsEmpty;
|
||||
|
||||
// События для внешних подписчиков
|
||||
public System.Action<Slot> OnSlotClicked;
|
||||
public System.Action<Slot> OnSlotRightClicked;
|
||||
public System.Action<Slot> OnSlotHovered;
|
||||
public System.Action<Slot> OnSlotDragStart;
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// Автоматическое получение компонентов если не назначены
|
||||
if (iconImage == null)
|
||||
iconImage = transform.Find("Icon")?.GetComponent<Image>();
|
||||
|
||||
if (amountText == null)
|
||||
amountText = transform.Find("AmountPanel/Text")?.GetComponent<TextMeshProUGUI>();
|
||||
|
||||
if (amountPanel == null)
|
||||
amountPanel = transform.Find("AmountPanel")?.gameObject;
|
||||
|
||||
if (slotBackground == null)
|
||||
slotBackground = GetComponent<Image>();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
UpdateSlotUI();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Обновить визуальное отображение слота
|
||||
/// </summary>
|
||||
public void UpdateSlotUI()
|
||||
{
|
||||
if (IsEmpty)
|
||||
{
|
||||
ClearVisuals();
|
||||
return;
|
||||
}
|
||||
|
||||
// Иконка
|
||||
if (item.icon != null)
|
||||
{
|
||||
iconImage.sprite = item.icon;
|
||||
iconImage.enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
iconImage.enabled = false;
|
||||
}
|
||||
|
||||
// Количество
|
||||
if (amount > 1)
|
||||
{
|
||||
amountText.text = amount.ToString();
|
||||
amountPanel.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
amountPanel.SetActive(false);
|
||||
}
|
||||
|
||||
// Цвет фона
|
||||
if (slotBackground != null)
|
||||
slotBackground.color = filledSlotColor;
|
||||
}
|
||||
|
||||
private void ClearVisuals()
|
||||
{
|
||||
iconImage.sprite = null;
|
||||
iconImage.enabled = false;
|
||||
amountPanel?.SetActive(false);
|
||||
|
||||
if (slotBackground != null)
|
||||
slotBackground.color = emptySlotColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Очистить слот
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
item = null;
|
||||
amount = 0;
|
||||
UpdateSlotUI();
|
||||
|
||||
// Уведомляем менеджер
|
||||
if (InventoryManager.Instance != null)
|
||||
{
|
||||
InventoryManager.Instance.OnSlotCleared(slotIndex);
|
||||
}
|
||||
|
||||
// Вызываем событие
|
||||
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Установить предмет в слот
|
||||
/// </summary>
|
||||
public void SetItem(ItemData newItem, int newAmount)
|
||||
{
|
||||
item = newItem;
|
||||
amount = newAmount;
|
||||
UpdateSlotUI();
|
||||
|
||||
// Вызываем событие изменения
|
||||
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item?.id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Добавить предметы в слот
|
||||
/// </summary>
|
||||
/// <returns>Количество не поместившихся предметов</returns>
|
||||
public int AddItems(ItemData newItem, int addAmount)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
// Пустой слот - просто кладём
|
||||
item = newItem;
|
||||
amount = Mathf.Min(addAmount, newItem.maxStack);
|
||||
UpdateSlotUI();
|
||||
|
||||
// Событие добавления
|
||||
InventoryEvents.Instance?.InvokeItemAdded(item.id, amount);
|
||||
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item.id);
|
||||
|
||||
return addAmount - amount;
|
||||
}
|
||||
|
||||
if (item.id != newItem.id)
|
||||
{
|
||||
// Другой предмет - нельзя добавить
|
||||
return addAmount;
|
||||
}
|
||||
|
||||
// Тот же предмет - пытаемся добавить в стек
|
||||
int space = item.maxStack - amount;
|
||||
if (space <= 0) return addAmount;
|
||||
|
||||
int toAdd = Mathf.Min(space, addAmount);
|
||||
amount += toAdd;
|
||||
UpdateSlotUI();
|
||||
|
||||
// Событие изменения
|
||||
InventoryEvents.Instance?.InvokeItemCountChanged(item.id, amount);
|
||||
InventoryEvents.Instance?.InvokeSlotChanged(slotIndex, item.id);
|
||||
|
||||
return addAmount - toAdd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Взять часть предметов из слота
|
||||
/// </summary>
|
||||
/// <returns>(предмет, взятое количество)</returns>
|
||||
public (ItemData, int) TakeItems(int takeAmount)
|
||||
{
|
||||
if (IsEmpty) return (null, 0);
|
||||
|
||||
int actualTake = Mathf.Min(takeAmount, amount);
|
||||
amount -= actualTake;
|
||||
|
||||
ItemData resultItem = item;
|
||||
|
||||
if (amount <= 0)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSlotUI();
|
||||
// Событие изменения количества
|
||||
InventoryEvents.Instance?.InvokeItemCountChanged(item.id, amount);
|
||||
}
|
||||
|
||||
// Событие удаления
|
||||
InventoryEvents.Instance?.InvokeItemRemoved(resultItem.id, actualTake);
|
||||
|
||||
return (resultItem, actualTake);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Взять все предметы из слота
|
||||
/// </summary>
|
||||
public (ItemData, int) TakeAll()
|
||||
{
|
||||
return TakeItems(amount);
|
||||
}
|
||||
|
||||
// ==================== UI Events ====================
|
||||
|
||||
void OnMouseEnter()
|
||||
{
|
||||
if (slotBackground != null && !_isSelected)
|
||||
slotBackground.color = hoverColor;
|
||||
|
||||
OnSlotHovered?.Invoke(this);
|
||||
}
|
||||
|
||||
void OnMouseExit()
|
||||
{
|
||||
if (slotBackground != null && !_isSelected)
|
||||
slotBackground.color = IsEmpty ? emptySlotColor : filledSlotColor;
|
||||
}
|
||||
|
||||
void OnMouseDown()
|
||||
{
|
||||
if (Input.GetMouseButton(0))
|
||||
{
|
||||
OnSlotClicked?.Invoke(this);
|
||||
|
||||
if (allowDrag)
|
||||
{
|
||||
OnSlotDragStart?.Invoke(this);
|
||||
}
|
||||
}
|
||||
else if (Input.GetMouseButton(1))
|
||||
{
|
||||
OnSlotRightClicked?.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Установить состояние выделения слота
|
||||
/// </summary>
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
_isSelected = selected;
|
||||
if (slotBackground != null)
|
||||
{
|
||||
slotBackground.color = selected ? selectedColor :
|
||||
(IsEmpty ? emptySlotColor : filledSlotColor);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Поменять содержимое с другим слотом
|
||||
/// </summary>
|
||||
public void SwapWith(Slot other)
|
||||
{
|
||||
if (other == null || other == this) return;
|
||||
|
||||
var tempItem = this.item;
|
||||
var tempAmount = this.amount;
|
||||
|
||||
this.SetItem(other.item, other.amount);
|
||||
other.SetItem(tempItem, tempAmount);
|
||||
}
|
||||
|
||||
// ==================== Getters ====================
|
||||
|
||||
public ItemData GetItem() => item;
|
||||
public int GetAmount() => amount;
|
||||
public string GetItemId() => item?.id;
|
||||
public bool IsSelected() => _isSelected;
|
||||
}
|
||||
Reference in New Issue
Block a user