using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
///
/// Конфигурация для фабрики предметов - создать в Assets > Create > Inventory > Item Factory Config
///
[CreateAssetMenu(fileName = "ItemFactoryConfig", menuName = "Inventory/Item Factory Config")]
public class ItemFactoryConfig : ScriptableObject
{
[Header("World Item Prefabs")]
public GameObject worldItemPrefab; // Префаб предмета в мире
[Header("Spawner Prefab")]
public GameObject itemSpawnerPrefab; // Префаб спавнера
[Header("Pickup Settings")]
public float pickupRadius = 1.5f;
public float despawnTime = 300f; // 5 минут
[Header("Drop Settings")]
public float dropForce = 2f;
public float dropRandomness = 0.5f;
}
///
/// Фабрика для создания префабов предметов - заменяет прямой Instantiate и Resources.Load
///
public class InventoryItemFactory : MonoBehaviour
{
public static InventoryItemFactory Instance { get; private set; }
[Header("Configuration")]
[Tooltip("Создать в Assets > Create > Inventory > Item Factory Config")]
public ItemFactoryConfig config;
[Header("Debug")]
public bool logSpawns = false;
// Кэшированные ссылки для быстрого доступа
private Dictionary _prefabCache = new Dictionary();
void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
///
/// Создать предмет в мире (WorldItem)
///
/// Данные предмета
/// Количество
/// Позиция спавна
/// rotation ( Quaternion.identity по умолчанию)
public WorldItem CreateWorldItem(ItemData itemData, int amount, Vector3 position, Quaternion rotation = default)
{
GameObject go;
if (config == null || config.worldItemPrefab == null)
{
// Fallback - создаём без префаба
go = new GameObject($"WorldItem_{itemData.itemName}");
go.transform.position = position;
go.transform.rotation = rotation;
// Добавляем компоненты для физики
var collider = go.AddComponent();
collider.radius = 0.3f;
collider.isTrigger = true;
var rb = go.AddComponent();
rb.isKinematic = true;
rb.useGravity = false;
}
else
{
go = Instantiate(config.worldItemPrefab, position, rotation);
}
var worldItem = go.GetComponent();
if (worldItem == null)
worldItem = go.AddComponent();
worldItem.Setup(itemData, amount);
if (logSpawns)
Debug.Log($"[Factory] Created WorldItem: {itemData.itemName} x{amount} at {position}");
return worldItem;
}
///
/// Создать предмет в мире с настраиваемым временем жизни
///
public WorldItem CreateWorldItem(ItemData itemData, int amount, Vector3 position, float lifetime, Quaternion rotation = default)
{
var worldItem = CreateWorldItem(itemData, amount, position, rotation);
if (worldItem != null && lifetime > 0)
{
Destroy(worldItem.gameObject, lifetime);
}
return worldItem;
}
///
/// Создать спавнер предмета (точка появления)
///
public ItemSpawner CreateItemSpawner(ItemData itemData, int amount, Vector3 position)
{
if (config == null || config.itemSpawnerPrefab == null)
{
// Создаём базовый спавнер без префаба
return CreateSpawnerFallback(itemData, amount, position);
}
var go = Instantiate(config.itemSpawnerPrefab, position, Quaternion.identity);
var spawner = go.GetComponent();
if (spawner == null)
spawner = go.AddComponent();
spawner.Setup(itemData, amount, config.despawnTime);
if (logSpawns)
Debug.Log($"[Factory] Created Spawner: {itemData.itemName} x{amount}");
return spawner;
}
private ItemSpawner CreateSpawnerFallback(ItemData itemData, int amount, Vector3 position)
{
var go = new GameObject($"Spawner_{itemData.itemName}");
go.transform.position = position;
var spawner = go.AddComponent();
spawner.Setup(itemData, amount, config != null ? config.despawnTime : 300f);
return spawner;
}
///
/// Выбросить предмет из инвентаря (drop)
///
public WorldItem DropItem(ItemData itemData, int amount, Vector3 dropPosition, Vector3? velocity = null)
{
// Добавляем небольшое случайное смещение
Vector3 offset = Vector3.zero;
if (config != null)
{
offset = new Vector3(
Random.Range(-config.dropRandomness, config.dropRandomness),
0.5f,
Random.Range(-config.dropRandomness, config.dropRandomness)
);
}
Vector3 spawnPos = dropPosition + offset;
Quaternion rotation = Quaternion.Euler(
Random.Range(0, 360),
Random.Range(0, 360),
Random.Range(0, 360)
);
var worldItem = CreateWorldItem(itemData, amount, spawnPos, rotation);
// Добавляем начальную скорость (для выброса из инвентаря)
if (velocity.HasValue && worldItem != null)
{
var rb = worldItem.GetComponent();
if (rb == null)
rb = worldItem.gameObject.AddComponent();
rb.linearVelocity = velocity.Value + (Vector3.up * (config?.dropForce ?? 2f));
}
return worldItem;
}
///
/// Предмет подбирается игроком - вызывается из WorldItem
///
public bool PickupItem(WorldItem worldItem, MonoBehaviour picker)
{
if (worldItem == null || worldItem.itemData == null)
return false;
int remaining = InventoryManager.Instance.AddItem(worldItem.itemData, worldItem.amount);
if (remaining <= 0)
{
if (logSpawns)
Debug.Log($"[Factory] Picked up: {worldItem.itemData.itemName} x{worldItem.amount}");
Destroy(worldItem.gameObject);
return true;
}
else
{
// Частичный подбор
worldItem.amount = remaining;
return false;
}
}
///
/// Создать префаб из GameObject в рантайме (динамические предметы)
///
public GameObject CreateItemModel(GameObject modelPrefab, Transform parent)
{
if (modelPrefab == null)
return null;
return Instantiate(modelPrefab, parent);
}
}
#if UNITY_EDITOR
///
/// Кастомный редактор для быстрой настройки фабрики
///
[CustomEditor(typeof(InventoryItemFactory))]
public class InventoryItemFactoryEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
var factory = (InventoryItemFactory)target;
GUILayout.Space(10);
if (factory.config == null)
{
EditorGUILayout.HelpBox(
"Создайте ItemFactoryConfig: Assets > Create > Inventory > Item Factory Config",
MessageType.Warning);
}
if (GUILayout.Button("Создать ItemFactoryConfig"))
{
var config = ScriptableObject.CreateInstance();
AssetDatabase.CreateAsset(config, "Assets/Inventory/Configs/ItemFactoryConfig.asset");
AssetDatabase.SaveAssets();
factory.config = config;
Debug.Log("Создан ItemFactoryConfig");
}
GUILayout.Space(5);
if (GUILayout.Button("Создать тестовый предмет в сцене"))
{
if (InventoryManager.Instance?.itemDatabase?.Count > 0)
{
var item = InventoryManager.Instance.itemDatabase[0];
factory.CreateWorldItem(item, 5, Vector3.zero + Vector3.forward * 2);
}
else
{
Debug.LogWarning("Сначала добавьте предметы в InventoryManager");
}
}
}
}
#endif