This commit is contained in:
jze9
2026-04-15 02:56:11 +05:00
parent 523bf475ca
commit 0837589fa2
1786 changed files with 236305 additions and 73082 deletions

View 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