Initial Unity project commit
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
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; // 置空该格子
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user