fack
This commit is contained in:
271
Assets/Inventory/Scripts/InventoryItemFactory.cs
Normal file
271
Assets/Inventory/Scripts/InventoryItemFactory.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Конфигурация для фабрики предметов - создать в Assets > Create > Inventory > Item Factory Config
|
||||
/// </summary>
|
||||
[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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика для создания префабов предметов - заменяет прямой Instantiate и Resources.Load
|
||||
/// </summary>
|
||||
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<string, GameObject> _prefabCache = new Dictionary<string, GameObject>();
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создать предмет в мире (WorldItem)
|
||||
/// </summary>
|
||||
/// <param name="itemData">Данные предмета</param>
|
||||
/// <param name="amount">Количество</param>
|
||||
/// <param name="position">Позиция спавна</param>
|
||||
/// <param name="rotation"> rotation ( Quaternion.identity по умолчанию)</param>
|
||||
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<SphereCollider>();
|
||||
collider.radius = 0.3f;
|
||||
collider.isTrigger = true;
|
||||
var rb = go.AddComponent<Rigidbody>();
|
||||
rb.isKinematic = true;
|
||||
rb.useGravity = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
go = Instantiate(config.worldItemPrefab, position, rotation);
|
||||
}
|
||||
var worldItem = go.GetComponent<WorldItem>();
|
||||
|
||||
if (worldItem == null)
|
||||
worldItem = go.AddComponent<WorldItem>();
|
||||
|
||||
worldItem.Setup(itemData, amount);
|
||||
|
||||
if (logSpawns)
|
||||
Debug.Log($"[Factory] Created WorldItem: {itemData.itemName} x{amount} at {position}");
|
||||
|
||||
return worldItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создать предмет в мире с настраиваемым временем жизни
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создать спавнер предмета (точка появления)
|
||||
/// </summary>
|
||||
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<ItemSpawner>();
|
||||
|
||||
if (spawner == null)
|
||||
spawner = go.AddComponent<ItemSpawner>();
|
||||
|
||||
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<ItemSpawner>();
|
||||
spawner.Setup(itemData, amount, config != null ? config.despawnTime : 300f);
|
||||
return spawner;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Выбросить предмет из инвентаря (drop)
|
||||
/// </summary>
|
||||
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<Rigidbody>();
|
||||
if (rb == null)
|
||||
rb = worldItem.gameObject.AddComponent<Rigidbody>();
|
||||
|
||||
rb.linearVelocity = velocity.Value + (Vector3.up * (config?.dropForce ?? 2f));
|
||||
}
|
||||
|
||||
return worldItem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Предмет подбирается игроком - вызывается из WorldItem
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создать префаб из GameObject в рантайме (динамические предметы)
|
||||
/// </summary>
|
||||
public GameObject CreateItemModel(GameObject modelPrefab, Transform parent)
|
||||
{
|
||||
if (modelPrefab == null)
|
||||
return null;
|
||||
|
||||
return Instantiate(modelPrefab, parent);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Кастомный редактор для быстрой настройки фабрики
|
||||
/// </summary>
|
||||
[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<ItemFactoryConfig>();
|
||||
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
|
||||
Reference in New Issue
Block a user