Files
Cielonos/Assets/Scripts/MainGame/Characters/Player/Inventory/BackpackSubmodule.cs
2026-05-10 11:47:55 -04:00

311 lines
12 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;
using System.Collections.Generic;
using Cielonos.MainGame.Characters.Inventory;
using Cielonos.MainGame.Characters.Inventory.Collections;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Cielonos.MainGame.Characters
{
public partial class PlayerInventorySubcontroller
{
public partial class BackpackSubmodule : SubmoduleBase<PlayerInventorySubcontroller>
{
public List<MainWeaponBase> mainWeapons = new List<MainWeaponBase>();
public List<SupportEquipmentBase> supportEquipments = new List<SupportEquipmentBase>();
public List<PassiveEquipmentBase> passiveEquipments = new List<PassiveEquipmentBase>();
public List<ConsumableBase> consumables = new List<ConsumableBase>();
/// <summary>
/// Resources 路径中道具类型对应的子文件夹名。
/// 约定路径格式Resources/Items/{子文件夹}/{类名}.prefab
/// </summary>
private static readonly Dictionary<Type, string> ItemTypeToSubfolder = new()
{
{ typeof(MainWeaponBase), "MainWeapon" },
{ typeof(SupportEquipmentBase), "SupportEquipment" },
{ typeof(PassiveEquipmentBase), "PassiveEquipment" },
{ typeof(ConsumableBase), "Consumable" },
};
public BackpackSubmodule(PlayerInventorySubcontroller owner) : base(owner)
{
}
}
// ================================================================
// 获取道具(已有实例)
// ================================================================
public partial class BackpackSubmodule
{
/// <summary>
/// 通过 Resources 加载 Prefab实例化到对应的 Container 下,然后加入背包。
/// 若为消耗品且背包中已存在同类型实例,则直接堆叠,不再重复生成。
/// </summary>
/// <typeparam name="T">道具的具体类型(必须继承 ItemBase。</typeparam>
/// <param name="amount">消耗品的初始 / 追加堆叠数量,非消耗品忽略此参数。</param>
/// <returns>背包中该道具的实例引用;加载失败时返回 null。</returns>
public T ObtainItem<T>(int amount = 1) where T : ItemBase
{
// 消耗品:如果背包中已有同类型实例,直接堆叠
if (typeof(ConsumableBase).IsAssignableFrom(typeof(T)))
{
ConsumableBase existing = consumables.Find(c => c is T);
if (existing != null)
{
existing.Add(amount);
return existing as T;
}
}
// 确定 Resources 子路径
string subfolder = ResolveSubfolder(typeof(T));
if (subfolder == null)
{
Debug.LogError($"[Backpack] 无法确定 {typeof(T).Name} 的 Resources 子文件夹。");
return null;
}
string resourcePath = $"Items/{subfolder}/{typeof(T).Name}";
GameObject prefab = Resources.Load<GameObject>(resourcePath);
if (prefab == null)
{
Debug.LogError($"[Backpack] 未找到 PrefabResources/{resourcePath}");
return null;
}
// 实例化到对应的 Container 下
Transform container = GetContainerForType(typeof(T));
GameObject instance = Object.Instantiate(prefab, container);
instance.name = typeof(T).Name;
T item = instance.GetComponent<T>();
if (item == null)
{
Debug.LogError($"[Backpack] Prefab '{resourcePath}' 上未找到组件 {typeof(T).Name}。");
Object.Destroy(instance);
return null;
}
ObtainItem(item, amount);
return item;
}
/// <summary>
/// 将已有的道具实例加入背包。
/// 对于消耗品amount 指定堆叠数量;-1 表示使用道具自身的 stackAmount。
/// </summary>
public void ObtainItem(ItemBase item, int amount = -1)
{
item.Initialize();
if (item is MainWeaponBase mainWeapon)
{
ObtainMainWeapon(mainWeapon);
}
else if (item is SupportEquipmentBase supportEquipment)
{
ObtainSupportEquipment(supportEquipment);
}
else if (item is PassiveEquipmentBase passiveEquipment)
{
ObtainPassiveEquipment(passiveEquipment);
}
else if (item is ConsumableBase consumable)
{
ObtainConsumable(consumable, amount);
}
item.OnObtained();
}
/// <summary>
/// 通过预制体引用获取道具:实例化到对应 Container 下并加入背包。
/// 消耗品会自动堆叠。用于 MechanicalTable、LogisticsCenter 等持有直接预制体引用的场景。
/// </summary>
/// <param name="prefab">道具预制体(必须包含 ItemBase 组件)。</param>
/// <param name="amount">消耗品的堆叠数量,非消耗品忽略。</param>
/// <returns>背包中该道具的实例引用;失败时返回 null。</returns>
public ItemBase ObtainItem(GameObject prefab, int amount = 1)
{
ItemBase prefabItem = prefab.GetComponent<ItemBase>();
if (prefabItem == null)
{
Debug.LogError($"[Backpack] Prefab '{prefab.name}' 上未找到 ItemBase 组件。");
return null;
}
// 消耗品:如果背包中已有同类型实例,直接堆叠
if (prefabItem is ConsumableBase)
{
ConsumableBase existing = consumables.Find(c => c.GetType() == prefabItem.GetType());
if (existing != null)
{
existing.Add(amount);
return existing;
}
}
Transform container = GetContainerForType(prefabItem.GetType());
GameObject instance = Object.Instantiate(prefab, container);
instance.name = prefabItem.GetType().Name;
ItemBase item = instance.GetComponent<ItemBase>();
if (item == null)
{
Debug.LogError($"[Backpack] 实例化后的 '{prefab.name}' 上未找到 ItemBase 组件。");
Object.Destroy(instance);
return null;
}
ObtainItem(item, amount);
return item;
}
public void DiscardItem(ItemBase item, int amount = -1)
{
if (item is MainWeaponBase mainWeapon)
{
DiscardMainWeapon(mainWeapon);
}
else if (item is SupportEquipmentBase supportEquipment)
{
DiscardSupportEquipment(supportEquipment);
}
else if (item is PassiveEquipmentBase passiveEquipment)
{
DiscardPassiveEquipment(passiveEquipment);
}
else if (item is ConsumableBase consumable)
{
DiscardConsumable(consumable, amount);
}
item.OnDiscarded();
}
}
// ================================================================
// 内部实现:获取 / 丢弃各类型道具
// ================================================================
public partial class BackpackSubmodule
{
private void ObtainMainWeapon(MainWeaponBase item)
{
if (!mainWeapons.Contains(item))
{
mainWeapons.Add(item);
}
}
private void DiscardMainWeapon(MainWeaponBase item)
{
if (mainWeapons.Contains(item))
{
mainWeapons.Remove(item);
}
}
private void ObtainSupportEquipment(SupportEquipmentBase item)
{
if (!supportEquipments.Contains(item))
{
supportEquipments.Add(item);
}
}
private void DiscardSupportEquipment(SupportEquipmentBase item)
{
if (supportEquipments.Contains(item))
{
supportEquipments.Remove(item);
}
}
private void ObtainPassiveEquipment(PassiveEquipmentBase item)
{
if (!passiveEquipments.Contains(item))
{
passiveEquipments.Add(item);
}
}
private void DiscardPassiveEquipment(PassiveEquipmentBase item)
{
if (passiveEquipments.Contains(item))
{
passiveEquipments.Remove(item);
}
}
private void ObtainConsumable(ConsumableBase item, int amount = -1)
{
ConsumableBase existingItem = consumables.Find(c => c.GetType() == item.GetType());
if (existingItem != null)
{
// 背包中已有同类型消耗品,堆叠
int stack = amount == -1 ? item.stackAmount : amount;
existingItem.Add(stack);
}
else
{
// 首次获得,加入列表并设置初始堆叠
consumables.Add(item);
if (amount >= 0)
{
item.stackAmount = amount;
}
}
}
private void DiscardConsumable(ConsumableBase item, int amount = -1)
{
if (consumables.Contains(item))
{
ConsumableBase existingItem = consumables.Find(consumable => consumable.GetType() == item.GetType());
existingItem.stackAmount -= amount == -1 ? item.stackAmount : amount; // 如果amount为-1则丢弃全部
if (existingItem.stackAmount <= 0)
{
consumables.Remove(existingItem);
}
}
}
}
// ================================================================
// 内部实现Resources 路径 / Container 解析
// ================================================================
public partial class BackpackSubmodule
{
/// <summary>
/// 根据道具具体类型查找其基类对应的 Resources 子文件夹名。
/// </summary>
private static string ResolveSubfolder(Type itemType)
{
foreach (var kvp in ItemTypeToSubfolder)
{
if (kvp.Key.IsAssignableFrom(itemType))
return kvp.Value;
}
return null;
}
/// <summary>
/// 根据道具类型返回对应的父级 Container Transform。
/// </summary>
private Transform GetContainerForType(Type itemType)
{
if (typeof(MainWeaponBase).IsAssignableFrom(itemType)) return owner.mainWeaponContainer;
if (typeof(SupportEquipmentBase).IsAssignableFrom(itemType)) return owner.supportEquipmentContainer;
if (typeof(PassiveEquipmentBase).IsAssignableFrom(itemType)) return owner.passiveEquipmentContainer;
if (typeof(ConsumableBase).IsAssignableFrom(itemType)) return owner.consumableContainer;
return owner.player.transform;
}
}
}
}