using UnityEngine; using UnityEngine.UI; using TMPro; /// /// Создаёт UI инвентаря программно. /// Вызывается ТОЛЬКО из редакторных инструментов (InventorySceneSetup, PlayerBuilderTool). /// Никакого runtime-создания: Start() отсутствует. /// public class InventoryUIBuilder : MonoBehaviour { [Header("Settings")] public int hotbarSlots = 9; public int inventoryRows = 4; public int inventoryCols = 9; [Header("Visual Settings")] public float slotSize = 50f; public float slotSpacing = 4f; public float inventoryPadding = 10f; public float hotbarPadding = 10f; [Header("Colors")] [SerializeField] private Color inventoryPanelColor = new Color(0.15f, 0.15f, 0.15f, 0.95f); [SerializeField] private Color hotbarPanelColor = new Color(0.1f, 0.1f, 0.1f, 0.9f); [SerializeField] private Color slotEmptyColor = new Color(0.25f, 0.25f, 0.25f, 0.8f); [Header("Container References")] public RectTransform inventoryPanelRect; public RectTransform hotbarPanelRect; public Canvas inventoryCanvas; // Созданные слоты — читаются редакторным инструментом после BuildInventoryUI() [SerializeField] private Slot[] _inventorySlots; [SerializeField] private Slot[] _hotbarSlots; public Slot[] GetInventorySlots() => _inventorySlots; public Slot[] GetHotbarSlots() => _hotbarSlots; // ── Построение UI ──────────────────────────────────────────────────────── public void BuildInventoryUI() { // Получаем или добавляем Canvas var canvas = GetComponent(); if (canvas == null) { canvas = gameObject.AddComponent(); canvas.renderMode = RenderMode.ScreenSpaceOverlay; canvas.sortingOrder = 100; gameObject.AddComponent(); } inventoryCanvas = canvas; // Панель инвентаря GameObject inventoryPanel = CreatePanel("InventoryPanel", transform, inventoryPanelColor); inventoryPanelRect = inventoryPanel.GetComponent(); float inventoryWidth = inventoryCols * slotSize + (inventoryCols - 1) * slotSpacing + inventoryPadding * 2; float inventoryHeight = inventoryRows * slotSize + (inventoryRows - 1) * slotSpacing + (inventoryPadding + 30) * 2; inventoryPanelRect.anchorMin = new Vector2(0.5f, 0.5f); inventoryPanelRect.anchorMax = new Vector2(0.5f, 0.5f); inventoryPanelRect.pivot = new Vector2(0.5f, 0.5f); inventoryPanelRect.anchoredPosition = Vector2.zero; inventoryPanelRect.sizeDelta = new Vector2(inventoryWidth, inventoryHeight); CreateTitle(inventoryPanel.transform, "Инвентарь", new Vector2(0, inventoryHeight / 2 - 20)); var inventoryGrid = CreateGrid( inventoryPanel.transform, "InventoryGrid", inventoryCols, inventoryRows, slotSize, slotSpacing, new Vector2(inventoryPadding, inventoryPadding + 30)); _inventorySlots = CreateSlots(inventoryGrid, "InventorySlot_", 0, inventoryCols * inventoryRows); // Хотбар GameObject hotbarPanel = CreatePanel("HotbarPanel", transform, hotbarPanelColor); hotbarPanelRect = hotbarPanel.GetComponent(); float hotbarWidth = hotbarSlots * (slotSize + slotSpacing) + hotbarPadding * 2; hotbarPanelRect.anchorMin = new Vector2(0.5f, 0f); hotbarPanelRect.anchorMax = new Vector2(0.5f, 0f); hotbarPanelRect.pivot = new Vector2(0.5f, 0f); hotbarPanelRect.anchoredPosition = new Vector2(0, 15); hotbarPanelRect.sizeDelta = new Vector2(hotbarWidth, slotSize + hotbarPadding * 2); var hotbarGrid = CreateGrid( hotbarPanel.transform, "HotbarGrid", hotbarSlots, 1, slotSize, slotSpacing, new Vector2(hotbarPadding, hotbarPadding)); _hotbarSlots = CreateSlots(hotbarGrid, "HotbarSlot_", 0, hotbarSlots); Debug.Log($"[InventoryUIBuilder] Built {inventoryCols * inventoryRows} inventory slots + {hotbarSlots} hotbar slots"); } // ── Вспомогательные методы ──────────────────────────────────────────────── GameObject CreatePanel(string name, Transform parent, Color color) { var panel = new GameObject(name); panel.transform.SetParent(parent, false); panel.AddComponent(); panel.AddComponent().color = color; return panel; } void CreateTitle(Transform parent, string text, Vector2 position) { var titleObj = new GameObject("Title"); titleObj.transform.SetParent(parent, false); var rect = titleObj.AddComponent(); rect.anchorMin = new Vector2(0, 1); rect.anchorMax = new Vector2(1, 1); rect.pivot = new Vector2(0.5f, 1); rect.anchoredPosition = position; rect.sizeDelta = new Vector2(-20, 30); var tmp = titleObj.AddComponent(); tmp.text = text; tmp.fontSize = 18; tmp.alignment = TextAlignmentOptions.Center; tmp.color = Color.white; } Transform CreateGrid(Transform parent, string name, int cols, int rows, float cellSize, float spacing, Vector2 offset) { var gridObj = new GameObject(name); gridObj.transform.SetParent(parent, false); var rect = gridObj.AddComponent(); rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = offset; rect.offsetMax = -offset; var grid = gridObj.AddComponent(); grid.cellSize = new Vector2(cellSize, cellSize); grid.spacing = new Vector2(spacing, spacing); grid.startCorner = GridLayoutGroup.Corner.UpperLeft; grid.startAxis = GridLayoutGroup.Axis.Horizontal; grid.constraint = GridLayoutGroup.Constraint.FixedColumnCount; grid.constraintCount = cols; grid.padding = new RectOffset(0, 0, 0, 0); return gridObj.transform; } Slot[] CreateSlots(Transform parent, string prefix, int startIndex, int count) { var slots = new Slot[count]; for (int i = 0; i < count; i++) { var slotObj = new GameObject(prefix + (startIndex + i)); slotObj.transform.SetParent(parent, false); var rect = slotObj.AddComponent(); rect.sizeDelta = new Vector2(slotSize, slotSize); var bg = slotObj.AddComponent(); bg.color = slotEmptyColor; var slot = slotObj.AddComponent(); slot.slotIndex = startIndex + i; slot.slotBackground = bg; // Иконка var iconObj = new GameObject("Icon"); iconObj.transform.SetParent(slotObj.transform, false); var iconRect = iconObj.AddComponent(); iconRect.anchorMin = Vector2.zero; iconRect.anchorMax = Vector2.one; iconRect.offsetMin = new Vector2(4, 4); iconRect.offsetMax = new Vector2(-4, -4); slot.iconImage = iconObj.AddComponent(); slot.iconImage.preserveAspect = true; slot.iconImage.enabled = false; // Количество var amountObj = new GameObject("AmountPanel"); amountObj.transform.SetParent(slotObj.transform, false); var amountRect = amountObj.AddComponent(); amountRect.anchorMin = Vector2.one; amountRect.anchorMax = Vector2.one; amountRect.pivot = new Vector2(1, 0); amountRect.anchoredPosition = new Vector2(-2, 2); amountRect.sizeDelta = new Vector2(22, 22); slot.amountPanel = amountObj; amountObj.AddComponent().color = new Color(0, 0, 0, 0.7f); var amountTextObj = new GameObject("Text"); amountTextObj.transform.SetParent(amountObj.transform, false); var amountTextRect = amountTextObj.AddComponent(); amountTextRect.anchorMin = Vector2.zero; amountTextRect.anchorMax = Vector2.one; slot.amountText = amountTextObj.AddComponent(); slot.amountText.fontSize = 14; slot.amountText.alignment = TextAlignmentOptions.Right; slot.amountText.color = Color.white; slot.amountText.fontStyle = FontStyles.Bold; slot.amountPanel.SetActive(false); // Drag & Drop var dragDrop = slotObj.AddComponent(); dragDrop.slot = slot; dragDrop.slotIndex = slot.slotIndex; slot.OnSlotClicked += OnSlotClicked; slots[i] = slot; } return slots; } // ── Выделение слота (runtime) ───────────────────────────────────────────── private int _selectedSlot = -1; private void OnSlotClicked(Slot slot) { if (_selectedSlot >= 0 && _inventorySlots != null && _selectedSlot < _inventorySlots.Length) _inventorySlots[_selectedSlot].SetSelected(false); slot.SetSelected(true); _selectedSlot = slot.slotIndex; Debug.Log($"[UI] Selected slot: {_selectedSlot} - {slot.GetItem()?.itemName ?? "Empty"}"); } // ── Утилиты ─────────────────────────────────────────────────────────────── public void Rebuild() { if (inventoryPanelRect != null) Destroy(inventoryPanelRect.gameObject); if (hotbarPanelRect != null) Destroy(hotbarPanelRect.gameObject); _inventorySlots = null; _hotbarSlots = null; BuildInventoryUI(); } public void ToggleInventory(bool show) { if (inventoryPanelRect != null) inventoryPanelRect.gameObject.SetActive(show); } }