235 lines
7.4 KiB
C#
235 lines
7.4 KiB
C#
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] 尝试添加空的 ItemData(referenceData 为 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; // 置空该格子
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|