Files
my-project/Assets/Inventory/Scripts/ItemBuilderTool.cs
unknown 087db550f1 bloak
2026-04-16 18:19:23 +05:00

282 lines
10 KiB
C#
Raw Permalink 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 UnityEngine;
using UnityEditor;
using TMPro;
/// <summary>
/// Инструмент создания предметов.
/// Tools > Item Builder
/// </summary>
public class ItemBuilderTool : EditorWindow
{
// Основные данные
private string itemName = "NewItem";
private string itemId = "";
private string description = "";
private ItemType itemType = ItemType.Material;
// Визуал
private GameObject modelPrefab;
private Sprite icon;
private Color previewColor = Color.gray;
// Свойства
private int maxStack = 64;
private int value = 1;
private float weight = 1f;
private bool isDroppable = true;
private bool isStackable = true;
// Pickup
private float interactRange = 2.5f;
[MenuItem("Tools/Item Builder")]
public static void ShowWindow()
{
GetWindow<ItemBuilderTool>("Конструктор Предметов");
}
void OnGUI()
{
GUILayout.Label("Создание предмета", EditorStyles.boldLabel);
// Основные данные
GUILayout.Label("Основное", EditorStyles.miniBoldLabel);
itemName = EditorGUILayout.TextField("Название", itemName);
itemId = EditorGUILayout.TextField("ID (оставь пустым для GUID)", itemId);
description = EditorGUILayout.TextField("Описание", description);
itemType = (ItemType)EditorGUILayout.EnumPopup("Тип предмета", itemType);
GUILayout.Space(10);
// Визуал
GUILayout.Label("Визуал", EditorStyles.miniBoldLabel);
modelPrefab = (GameObject)EditorGUILayout.ObjectField("3D модель (префаб)", modelPrefab, typeof(GameObject), false);
icon = (Sprite)EditorGUILayout.ObjectField("Иконка", icon, typeof(Sprite), false);
if (icon == null)
previewColor = EditorGUILayout.ColorField("Цвет иконки (заглушка)", previewColor);
GUILayout.Space(10);
// Свойства
GUILayout.Label("Свойства", EditorStyles.miniBoldLabel);
maxStack = EditorGUILayout.IntField("Макс. стек", maxStack);
value = EditorGUILayout.IntField("Цена", value);
weight = EditorGUILayout.FloatField("Вес", weight);
isDroppable = EditorGUILayout.Toggle("Можно выбросить", isDroppable);
isStackable = EditorGUILayout.Toggle("Стекируемый", isStackable);
GUILayout.Space(10);
GUILayout.Label("Подбор", EditorStyles.miniBoldLabel);
interactRange = EditorGUILayout.FloatField("Дальность подбора (E)", interactRange);
GUILayout.Space(20);
// Кнопки
GUI.color = Color.green;
if (GUILayout.Button("Создать ItemData (ScriptableObject)"))
CreateItemData();
GUI.color = Color.cyan;
if (GUILayout.Button("Создать WorldItem в сцене"))
CreateWorldItem();
GUI.color = Color.yellow;
if (GUILayout.Button("Создать WorldItem как префаб"))
CreateItemPrefab();
GUI.color = Color.white;
GUILayout.Space(10);
EditorGUILayout.HelpBox(
"Подбор предметов — только по кнопке E (авто-pickup при касании убран намеренно).\n" +
"1. Заполните данные → Создайте ItemData\n" +
"2. Назначьте ItemData в InventoryManager.itemDatabase\n" +
"3. Создайте WorldItem для размещения предметов на сцене",
MessageType.Info);
}
void CreateItemData()
{
if (string.IsNullOrEmpty(itemName))
{
EditorUtility.DisplayDialog("Ошибка", "Введите название предмета", "OK");
return;
}
var item = ScriptableObject.CreateInstance<ItemData>();
item.id = string.IsNullOrEmpty(itemId) ? System.Guid.NewGuid().ToString() : itemId;
item.itemName = itemName;
item.description = description;
item.type = itemType;
item.modelPrefab = modelPrefab;
item.icon = icon ?? CreatePlaceholderIcon();
item.maxStack = maxStack;
item.value = value;
item.weight = weight;
item.isDroppable = isDroppable;
item.isStackable = isStackable;
string folder = "Assets/Inventory/Items";
if (!System.IO.Directory.Exists(folder))
System.IO.Directory.CreateDirectory(folder);
string path = $"{folder}/{itemName}.asset";
AssetDatabase.CreateAsset(item, path);
AssetDatabase.SaveAssets();
Selection.activeObject = item;
Debug.Log($"[ItemBuilder] Создан: {itemName} → {path}");
}
void CreateWorldItem()
{
var itemGO = new GameObject(itemName);
// Визуал
GameObject visual;
if (modelPrefab != null)
{
visual = (GameObject)PrefabUtility.InstantiatePrefab(modelPrefab, itemGO.transform);
}
else
{
visual = GameObject.CreatePrimitive(PrimitiveType.Cube);
visual.transform.SetParent(itemGO.transform, false);
visual.transform.localScale = Vector3.one * 0.3f;
DestroyImmediate(visual.GetComponent<Collider>());
}
visual.name = "Visual";
visual.transform.localPosition = Vector3.zero;
// WorldItem компонент
var worldItem = itemGO.AddComponent<WorldItem>();
worldItem.interactRange = interactRange;
// Автоматически создаём/находим ItemData и назначаем
var data = EnsureItemData();
if (data != null)
{
worldItem.itemData = data;
AddToInventoryDatabase(data);
}
// Trigger-коллайдер для OverlapSphere (не для авто-pickup!)
var col = itemGO.AddComponent<SphereCollider>();
col.radius = 0.5f;
col.isTrigger = true;
itemGO.transform.position = Vector3.zero;
Selection.activeGameObject = itemGO;
Debug.Log($"[ItemBuilder] Создан WorldItem: {itemName}");
}
void CreateItemPrefab()
{
string path = EditorUtility.SaveFilePanelInProject(
"Сохранить WorldItem префаб",
itemName,
"prefab",
"Выберите место сохранения");
if (string.IsNullOrEmpty(path)) return;
var prefabGO = new GameObject(itemName);
// Визуал
GameObject visual;
if (modelPrefab != null)
{
visual = (GameObject)PrefabUtility.InstantiatePrefab(modelPrefab, prefabGO.transform);
}
else
{
visual = GameObject.CreatePrimitive(PrimitiveType.Cube);
visual.transform.SetParent(prefabGO.transform, false);
visual.transform.localScale = Vector3.one * 0.3f;
DestroyImmediate(visual.GetComponent<Collider>());
}
visual.name = "Visual";
visual.transform.localPosition = Vector3.zero;
var worldItem = prefabGO.AddComponent<WorldItem>();
worldItem.interactRange = interactRange;
var data = EnsureItemData();
if (data != null)
{
worldItem.itemData = data;
AddToInventoryDatabase(data);
}
var col = prefabGO.AddComponent<SphereCollider>();
col.radius = 0.5f;
col.isTrigger = true;
GameObject savedPrefab = PrefabUtility.SaveAsPrefabAsset(prefabGO, path);
DestroyImmediate(prefabGO);
Selection.activeObject = savedPrefab;
Debug.Log($"[ItemBuilder] Префаб сохранён: {path}");
}
// Находит существующий ItemData ассет или создаёт новый — без диалогов
ItemData EnsureItemData()
{
string folder = "Assets/Inventory/Items";
string path = $"{folder}/{itemName}.asset";
var existing = AssetDatabase.LoadAssetAtPath<ItemData>(path);
if (existing != null) return existing;
if (!System.IO.Directory.Exists(folder))
System.IO.Directory.CreateDirectory(folder);
var item = ScriptableObject.CreateInstance<ItemData>();
item.id = string.IsNullOrEmpty(itemId) ? System.Guid.NewGuid().ToString() : itemId;
item.itemName = itemName;
item.description = description;
item.type = itemType;
item.modelPrefab = modelPrefab;
item.icon = icon ?? CreatePlaceholderIcon();
item.maxStack = maxStack;
item.value = value;
item.weight = weight;
item.isDroppable = isDroppable;
item.isStackable = isStackable;
AssetDatabase.CreateAsset(item, path);
AssetDatabase.SaveAssets();
Debug.Log($"[ItemBuilder] ItemData автоматически создан: {path}");
return item;
}
// Добавляет ItemData в InventoryManager.itemDatabase если его там нет
void AddToInventoryDatabase(ItemData data)
{
var im = Object.FindObjectOfType<InventoryManager>();
if (im == null) return;
if (im.itemDatabase == null)
im.itemDatabase = new System.Collections.Generic.List<ItemData>();
if (!im.itemDatabase.Contains(data))
{
im.itemDatabase.Add(data);
EditorUtility.SetDirty(im);
Debug.Log($"[ItemBuilder] {data.itemName} добавлен в InventoryManager.itemDatabase");
}
}
Sprite CreatePlaceholderIcon()
{
var tex = new Texture2D(64, 64);
var colors = new Color[64 * 64];
for (int i = 0; i < colors.Length; i++)
colors[i] = previewColor;
tex.SetPixels(colors);
tex.Apply();
return Sprite.Create(tex, new Rect(0, 0, 64, 64), new Vector2(0.5f, 0.5f));
}
}