using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class TalentTreeUI : MonoBehaviour { public TalentManager manager; public PlayerStats playerStats; [Header("Tree")] public GameObject panelRoot; public RectTransform lineRoot; public RectTransform nodesRoot; public TalentNodeUI nodePrefab; public TalentTooltipUI tooltip; [Header("Panels")] public Text titleText; public Text pointsText; public Text controlsText; public StatsPanelUI statsPanel; [Header("Buttons")] public Button saveButton; public Button loadButton; public Button resetButton; public bool openOnStart; private readonly List nodes = new List(); private readonly List lines = new List(); private bool isOpen; private void Awake() { if (manager == null) { manager = FindObjectOfType(); } if (playerStats == null) { playerStats = FindObjectOfType(); } } private void OnEnable() { if (manager != null) { manager.OnTalentStateChanged += Refresh; } } private void OnDisable() { if (manager != null) { manager.OnTalentStateChanged -= Refresh; } } private void Start() { BindButtons(); BuildTree(); Refresh(); SetOpen(openOnStart); } private void Update() { if (Input.GetKeyDown(KeyCode.K)) { Toggle(); } } public void Toggle() { SetOpen(!isOpen); } public void SetOpen(bool open) { isOpen = open; if (panelRoot != null) { panelRoot.SetActive(open); } if (open) { Refresh(); UpdateLines(); } } public void BuildTree() { ClearChildren(nodesRoot); ClearChildren(lineRoot); nodes.Clear(); lines.Clear(); if (manager == null || nodePrefab == null || nodesRoot == null) { return; } Dictionary nodeByTalent = new Dictionary(); for (int i = 0; i < manager.allTalents.Count; i++) { TalentData talent = manager.allTalents[i]; if (talent == null) { continue; } TalentNodeUI node = Instantiate(nodePrefab, nodesRoot); node.gameObject.SetActive(true); node.tooltip = tooltip; node.Setup(talent, manager); RectTransform rectTransform = node.transform as RectTransform; if (rectTransform != null) { rectTransform.anchoredPosition = talent.treePosition; } nodes.Add(node); nodeByTalent[talent] = node; } if (lineRoot == null) { return; } for (int i = 0; i < manager.allTalents.Count; i++) { TalentData talent = manager.allTalents[i]; if (talent == null || talent.prerequisites == null) { continue; } for (int prerequisiteIndex = 0; prerequisiteIndex < talent.prerequisites.Length; prerequisiteIndex++) { TalentData prerequisite = talent.prerequisites[prerequisiteIndex]; if (prerequisite == null || !nodeByTalent.ContainsKey(prerequisite) || !nodeByTalent.ContainsKey(talent)) { continue; } LineConnectorUI line = CreateLine(lineRoot, prerequisite, nodeByTalent[prerequisite], nodeByTalent[talent]); lines.Add(line); } } UpdateLines(); } public void Refresh() { if (titleText != null) { titleText.text = "Дерево талантов"; } if (pointsText != null) { int points = manager != null ? manager.GetAvailableTalentPoints() : 0; pointsText.text = $"Очки талантов: {points}"; } if (controlsText != null) { controlsText.text = "K - дерево X - +50 XP T - +1 очко E - кристалл F5 - сохранить F9 - загрузить Backspace - сброс"; } for (int i = 0; i < nodes.Count; i++) { if (nodes[i] != null) { nodes[i].Refresh(); } } if (statsPanel != null) { statsPanel.Refresh(); } UpdateLines(); } private void BindButtons() { if (saveButton != null) { saveButton.onClick.RemoveAllListeners(); saveButton.onClick.AddListener(() => { if (manager != null) { manager.SaveProgress(); } }); } if (loadButton != null) { loadButton.onClick.RemoveAllListeners(); loadButton.onClick.AddListener(() => { if (manager != null) { manager.LoadProgress(); } }); } if (resetButton != null) { resetButton.onClick.RemoveAllListeners(); resetButton.onClick.AddListener(() => { if (manager != null) { manager.ResetProgress(); } }); } } private LineConnectorUI CreateLine(RectTransform parent, TalentData childTalent, TalentNodeUI startNode, TalentNodeUI endNode) { GameObject lineObject = new GameObject($"Line_{startNode.talent.talentId}_to_{childTalent.talentId}", typeof(RectTransform), typeof(Image), typeof(LineConnectorUI)); lineObject.transform.SetParent(parent, false); Image image = lineObject.GetComponent(); Color color = childTalent.branchColor; image.color = new Color(color.r, color.g, color.b, 0.72f); image.raycastTarget = false; LineConnectorUI connector = lineObject.GetComponent(); connector.lineImage = image; connector.thickness = 5f; connector.dynamicUpdate = true; connector.SetEndpoints(startNode.transform as RectTransform, endNode.transform as RectTransform); return connector; } private void UpdateLines() { Canvas.ForceUpdateCanvases(); for (int i = 0; i < lines.Count; i++) { if (lines[i] != null) { lines[i].UpdateLine(); } } } private void ClearChildren(RectTransform root) { if (root == null) { return; } for (int i = root.childCount - 1; i >= 0; i--) { Destroy(root.GetChild(i).gameObject); } } }