Files
Echo/Assets/_Project/Scripts/Inventory/InventorySystem.cs
T
2026-07-08 20:42:51 +08:00

235 lines
7.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using UnityEngine;
namespace Inventory
{
[System.Serializable]
public class InventoryItem
{
public ItemData data;
public int stackSize;
public InventoryItem(ItemData source, int amount)
{
data = source;
stackSize = amount;
}
public void AddToStack(int amount)
{
stackSize += amount;
}
public void RemoveFromStack(int amount)
{
stackSize -= amount;
}
}
public class InventorySystem : MonoBehaviour
{
[Header("背包配置")]
[Tooltip("背包最大格子数")]
public int maxSlots = 20;
// 背包内容列表
public List<InventoryItem> inventory = new List<InventoryItem>();
// 当前选中的格子索引(由 InventoryUI 同步)
public int selectedSlotIndex = 0;
// 这是一个简单的单例模式,方便全局访问(但在大项目中建议用依赖注入)
public static InventorySystem Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
}
else
{
Instance = this;
// 初始化固定大小的背包,填充 null
InitializeInventory();
SanitizeInventory();
}
}
private void InitializeInventory()
{
inventory.Clear();
for (int i = 0; i < maxSlots; i++)
{
inventory.Add(null);
}
}
private void SanitizeInventory()
{
if (inventory == null) inventory = new List<InventoryItem>();
if (inventory.Count > maxSlots)
{
inventory.RemoveRange(maxSlots, inventory.Count - maxSlots);
}
else
{
while (inventory.Count < maxSlots)
{
inventory.Add(null);
}
}
for (int i = 0; i < inventory.Count; i++)
{
InventoryItem item = inventory[i];
if (item == null) continue;
if (item.data == null || item.stackSize <= 0)
{
inventory[i] = null;
}
}
}
/// <summary>
/// 添加物品到背包
/// </summary>
/// <param name="referenceData">物品数据</param>
/// <param name="amount">添加数量</param>
/// <returns>是否成功添加(哪怕只添加了一部分也算成功)</returns>
public bool Add(ItemData referenceData, int amount)
{
if (referenceData == null)
{
Debug.LogError("[Inventory] 尝试添加空的 ItemDatareferenceData 为 null)。");
return false;
}
if (amount <= 0) return false;
SanitizeInventory();
// 剩余需要添加的数量
int remainingAmount = amount;
// 1. 如果物品可堆叠,先尝试填满已有的堆叠
if (referenceData.isStackable)
{
// 遍历所有格子寻找同类物品
for (int i = 0; i < inventory.Count; i++)
{
InventoryItem item = inventory[i];
if (item != null && item.data == referenceData)
{
// 如果这个堆叠还没满
if (item.stackSize < referenceData.maxStackSize)
{
// 计算这个格子还能塞多少个
int spaceInStack = referenceData.maxStackSize - item.stackSize;
// 实际能塞进去的数量
int amountToAdd = Mathf.Min(remainingAmount, spaceInStack);
item.AddToStack(amountToAdd);
remainingAmount -= amountToAdd;
Debug.Log($"[Inventory] 堆叠更新: {referenceData.displayName}, 当前堆叠数: {item.stackSize}");
if (remainingAmount <= 0) return true;
}
}
}
}
// 2. 如果还有剩余,寻找新格子
while (remainingAmount > 0)
{
int targetSlotIndex = -1;
// 优先级 A: 检查当前选中的格子是否为空
if (selectedSlotIndex >= 0 && selectedSlotIndex < maxSlots && inventory[selectedSlotIndex] == null)
{
targetSlotIndex = selectedSlotIndex;
}
// 优先级 B: 如果选中格子不空,从头寻找第一个空位
else
{
for (int i = 0; i < maxSlots; i++)
{
if (inventory[i] == null)
{
targetSlotIndex = i;
break;
}
}
}
// 如果没找到空位,说明背包满了
if (targetSlotIndex == -1)
{
Debug.LogWarning("[Inventory] 背包已满!无法添加更多物品。");
return remainingAmount < amount;
}
// 创建新物品项并填入目标格子
int addCount = referenceData.isStackable ? Mathf.Min(remainingAmount, referenceData.maxStackSize) : 1;
InventoryItem newItem = new InventoryItem(referenceData, addCount);
inventory[targetSlotIndex] = newItem; // 填入空位
remainingAmount -= addCount;
Debug.Log($"[Inventory] 添加新物品到格子 {targetSlotIndex}: {referenceData.displayName}, 数量: {addCount}");
}
return true;
}
public void Remove(ItemData referenceData, int amount)
{
if (referenceData == null) return;
if (amount <= 0) return;
SanitizeInventory();
int remaining = amount;
for (int i = 0; i < inventory.Count; i++)
{
InventoryItem item = inventory[i];
if (item == null) continue;
if (item.data != referenceData) continue;
int take = Mathf.Min(remaining, item.stackSize);
item.RemoveFromStack(take);
remaining -= take;
if (item.stackSize <= 0)
{
inventory[i] = null;
}
if (remaining <= 0) break;
}
}
/// <summary>
/// 从指定格子移除物品
/// </summary>
public void RemoveFromSlot(int slotIndex, int amount)
{
SanitizeInventory();
if (slotIndex < 0 || slotIndex >= inventory.Count) return;
InventoryItem item = inventory[slotIndex];
if (item != null)
{
item.RemoveFromStack(amount);
if (item.stackSize <= 0)
{
inventory[slotIndex] = null; // 置空该格子
}
}
}
}
}