private AbilityTreeButton AddButton(AbilityTree.AbilityTreeNode node) { if (!_buttonsById.ContainsKey(node.ability.id)) { GameObject buttonGO = GameObject.Instantiate(_buttonPrototype, transform); buttonGO.SetActive(true); AbilityTreeButton button = buttonGO.GetComponent <AbilityTreeButton>(); button.Setup(this, node.ability); _buttonsById.Add(node.ability.id, button); _buttons.Add(button); if (node.parent == null) { Transform linkFrom = button.transform.Find("LinkFrom"); linkFrom.gameObject.SetActive(false); } Transform linkToGroup = button.transform.Find("LinkToGroup"); if (node.unlocks.Count == 0) { linkToGroup.gameObject.SetActive(false); } else { RectTransform joiner = linkToGroup.Find("Joiner") as RectTransform; joiner.sizeDelta = new Vector2(((node.unlocks.Count - 1) * 200f) + 4f, 4f); } return(button); } return(null); }
public void BuildAbilityTree(AbilityTree abilityTree) { _buttons = new List <AbilityTreeButton>(); _buttonsById = new Dictionary <string, AbilityTreeButton>(); int treeBreadth = abilityTree.rootAbilities.Count; // The max count of abilities at any depth int treeDepth = 1; List <int> breadthPerDepthLevel = new List <int>(); List <List <AbilityTree.AbilityTreeNode> > depthLevels = new List <List <AbilityTree.AbilityTreeNode> >(); breadthPerDepthLevel.Add(abilityTree.rootAbilities.Count); float initialYOffset = 100f; float minXDistanceBetweenButtons = 200f; float minYDistanceBetweenButtons = 200f; int widestDepth = 0; int curTreeDepth = 0; // Do the root nodes first and seperately List <AbilityTree.AbilityTreeNode> curAbilityTreeBreadthList = new List <AbilityTree.AbilityTreeNode>(); depthLevels.Add(curAbilityTreeBreadthList); List <AbilityTree.AbilityTreeNode> childAbilityTreeBreadthList = new List <AbilityTree.AbilityTreeNode>(); for (int i = 0; i < abilityTree.rootAbilities.Count; i++) { AbilityTree.AbilityTreeNode node = abilityTree.rootAbilities[i]; curAbilityTreeBreadthList.Add(node); foreach (AbilityTree.AbilityTreeNode child in node.unlocks) { childAbilityTreeBreadthList.Add(child); } AbilityTreeButton button = AddButton(node); RectTransform t = button.transform as RectTransform; float xPos = (i * minXDistanceBetweenButtons) - ((breadthPerDepthLevel[curTreeDepth] - 1) * minXDistanceBetweenButtons / 2); t.anchoredPosition = new Vector2(xPos, initialYOffset + minYDistanceBetweenButtons * curTreeDepth); } while (childAbilityTreeBreadthList.Count > 0) { curTreeDepth++; treeDepth++; curAbilityTreeBreadthList = childAbilityTreeBreadthList; depthLevels.Add(curAbilityTreeBreadthList); breadthPerDepthLevel.Add(curAbilityTreeBreadthList.Count); if (curAbilityTreeBreadthList.Count > treeBreadth) { widestDepth = curTreeDepth; treeBreadth = curAbilityTreeBreadthList.Count; } childAbilityTreeBreadthList = new List <AbilityTree.AbilityTreeNode>(); for (int i = 0; i < curAbilityTreeBreadthList.Count; i++) { AbilityTree.AbilityTreeNode node = curAbilityTreeBreadthList[i]; foreach (AbilityTree.AbilityTreeNode child in node.unlocks) { childAbilityTreeBreadthList.Add(child); } AbilityTreeButton button = AddButton(node); RectTransform t = button.transform as RectTransform; float xPos = (i * minXDistanceBetweenButtons) - ((breadthPerDepthLevel[curTreeDepth] - 1) * minXDistanceBetweenButtons / 2); t.anchoredPosition = new Vector2(xPos, initialYOffset + minYDistanceBetweenButtons * curTreeDepth); } } List <List <Vector2> > spaceUsed = new List <List <Vector2> >(); float minXOffset = 0f; float maxXOffset = 0f; HashSet <AbilityTree.AbilityTreeNode> alreadyAdjusted = new HashSet <AbilityTree.AbilityTreeNode>(); // Adjust positions moving up from widest for (int i = widestDepth; i < treeDepth; i++) { List <AbilityTree.AbilityTreeNode> treeNodes = depthLevels[i]; float childYPos = initialYOffset + minYDistanceBetweenButtons * (i + 1); foreach (AbilityTree.AbilityTreeNode node in treeNodes) { _buttonsById.TryGetValue(node.ability.id, out AbilityTreeButton parentButton); RectTransform parentTransform = parentButton.transform as RectTransform; minXOffset = Mathf.Min(minXOffset, parentTransform.anchoredPosition.x); maxXOffset = Mathf.Max(maxXOffset, parentTransform.anchoredPosition.x); if (node.unlocks.Count > 0) // Has children to adjust { float centerX = parentTransform.anchoredPosition.x; for (int index = 0; index < node.unlocks.Count; index++) { AbilityTree.AbilityTreeNode child = node.unlocks[index]; _buttonsById.TryGetValue(child.ability.id, out AbilityTreeButton childButton); RectTransform childTransform = childButton.transform as RectTransform; float xpos = (index * minXDistanceBetweenButtons) - ((node.unlocks.Count - 1) * minXDistanceBetweenButtons / 2) + centerX; childTransform.anchoredPosition = new Vector2(xpos, childYPos); alreadyAdjusted.Add(child); } } } } // Adjust positions moving down from widest for (int i = widestDepth - 1; i >= 0; i--) { List <AbilityTree.AbilityTreeNode> treeNodes = depthLevels[i]; float childYPos = initialYOffset + minYDistanceBetweenButtons * (i); foreach (AbilityTree.AbilityTreeNode node in treeNodes) { _buttonsById.TryGetValue(node.ability.id, out AbilityTreeButton parentButton); RectTransform parentTransform = parentButton.transform as RectTransform; minXOffset = Mathf.Min(minXOffset, parentTransform.anchoredPosition.x); maxXOffset = Mathf.Max(maxXOffset, parentTransform.anchoredPosition.x); if (node.unlocks.Count > 0) // Has children to adjust by { // First adjust child siblings that haven't already been adjusted for (int c = 0; c < node.unlocks.Count; c++) { AbilityTree.AbilityTreeNode childNode = node.unlocks[c]; if (!alreadyAdjusted.Contains(childNode)) { _buttonsById.TryGetValue(childNode.ability.id, out AbilityTreeButton childButton); RectTransform childTransform = childButton.transform as RectTransform; // Check Left if (c > 0) { AbilityTree.AbilityTreeNode siblingNode = node.unlocks[c - 1]; _buttonsById.TryGetValue(siblingNode.ability.id, out AbilityTreeButton siblingButton); RectTransform siblingTransform = siblingButton.transform as RectTransform; if (childTransform.anchoredPosition.x - siblingTransform.anchoredPosition.x < minXDistanceBetweenButtons) { float newX = siblingTransform.anchoredPosition.x + minXDistanceBetweenButtons; childTransform.anchoredPosition = new Vector2(newX, childTransform.anchoredPosition.y); minXOffset = Mathf.Min(minXOffset, newX); maxXOffset = Mathf.Max(maxXOffset, newX); } } // Check Right if (c < node.unlocks.Count - 1) { AbilityTree.AbilityTreeNode siblingNode = node.unlocks[c + 1]; _buttonsById.TryGetValue(siblingNode.ability.id, out AbilityTreeButton siblingButton); RectTransform siblingTransform = siblingButton.transform as RectTransform; if (siblingTransform.anchoredPosition.x - childTransform.anchoredPosition.x < minXDistanceBetweenButtons) { float newX = siblingTransform.anchoredPosition.x - minXDistanceBetweenButtons; childTransform.anchoredPosition = new Vector2(newX, childTransform.anchoredPosition.y); minXOffset = Mathf.Min(minXOffset, newX); maxXOffset = Mathf.Max(maxXOffset, newX); } } } } float centerX = parentTransform.anchoredPosition.x; AbilityTree.AbilityTreeNode c1 = node.unlocks[0]; AbilityTree.AbilityTreeNode c2 = node.unlocks[node.unlocks.Count - 1]; _buttonsById.TryGetValue(c1.ability.id, out AbilityTreeButton c1Button); _buttonsById.TryGetValue(c2.ability.id, out AbilityTreeButton c2Button); RectTransform c1Transform = c1Button.transform as RectTransform; RectTransform c2Transform = c2Button.transform as RectTransform; float width = Mathf.Abs((c1Transform.anchoredPosition.x - c2Transform.anchoredPosition.x)); float xpos = (c1Transform.anchoredPosition.x + c2Transform.anchoredPosition.x) / 2; parentTransform.anchoredPosition = new Vector2(xpos, childYPos); alreadyAdjusted.Add(node); Transform linkToGroup = parentTransform.Find("LinkToGroup"); RectTransform joiner = linkToGroup.Find("Joiner") as RectTransform; joiner.sizeDelta = new Vector2(width + 4f, 4f); } } } RectTransform thisTransform = transform as RectTransform; thisTransform.offsetMax = new Vector2(maxXOffset + 100f, treeDepth * minYDistanceBetweenButtons); thisTransform.offsetMin = new Vector2(minXOffset - 100f, 0f); Populate(); }