Files

235 lines
7.4 KiB
C#
Raw Permalink Normal View History

2026-07-08 19:53:15 +08:00
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; // 置空该格子
}
}
}
}
}