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; // 置空该格子
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|