I’m trying to make a module that will dynamically create a skill tree visually on the client. The issue I’m having is making it so nodes don’t overlap I’ve tried a few things but I am completely stumped.
here is how hierarchy is setup Base is the directory that I want to turn into a tree
--LOCAL SCRIPT
local Frame = script.Parent.TestFrame
local NodeDrawlerObj = require(script.Parent.NodeDrawler)
local NodeDrawler = NodeDrawlerObj.new(Frame, script.Parent.Base)
--Main Module
local NodeObj = require(script.CreateNode)
local NodeDrawler = {}
NodeDrawler.__index = NodeDrawler
function NodeDrawler.new(TargetFrame, TargetTree)
local self = setmetatable({}, NodeDrawler)
self.TargetTree = TargetTree
self.TargetFrame = TargetFrame
local MainNode = nil
local function Recurse(Target, ParentNode)
local ChildArray = Target:GetChildren()
for Index, CurrentNodeObj in pairs(ChildArray) do
if #CurrentNodeObj:GetChildren() > 0 then
local Node = NodeObj.new(self, Index, CurrentNodeObj, ParentNode)
if MainNode == nil then
MainNode = Node
else
ParentNode:AddChildNode(Node)
end
Recurse(CurrentNodeObj, Node)
else
local Node = NodeObj.new(self, Index, CurrentNodeObj, ParentNode)
ParentNode:AddChildNode(Node)
end
end
end
Recurse(TargetTree)
local function UpdatePosRecursion(Target)
for i,v in pairs(Target) do
v:UpdatePosition()
UpdatePosRecursion(v.ChildNodes)
end
end
UpdatePosRecursion(MainNode.ChildNodes)
return self
end
function NodeDrawler:ConnectNodes(ParentNode, ChildNode)
local StartX, StartY = ParentNode.UI.Position.X.Offset, ParentNode.UI.Position.Y.Offset
local EndX, EndY = ChildNode.UI.Position.X.Offset, ChildNode.UI.Position.Y.Offset
local Frame = Instance.new("Frame")
Frame.AnchorPoint = Vector2.new(0.5, 0.5)
Frame.Size = UDim2.new(0, (math.sqrt((EndX-StartX)^2+(EndY-StartY)^2)), 0, 1)
Frame.Position = UDim2.new(.5,(StartX+EndX)/2, 0, (StartY+EndY)/2)
Frame.Rotation = math.atan2(EndY-StartY, EndX-StartX)*(180/math.pi)
Frame.Parent = self.TargetFrame
end
return NodeDrawler
--Sub module
local Node = {}
Node.__index = Node
local GuiSize = UDim2.new(0,50,0,50)
local GapSizeX = 50
local GapSizeY = 25
function Node.new(NodeDrawler, Index, CurrentNodeObj, ParentNode)
local self = setmetatable({}, Node)
self.NodeDrawler = NodeDrawler
self.Modify = 0
self.ChildArray = CurrentNodeObj:GetChildren()
self.ChildNodes = {}
self.Index = Index
self.CurrentNodeObj = CurrentNodeObj
self.ParentNode = ParentNode
self:DrawNode()
return self
end
function Node:UpdatePosition()
if self.ParentNode ~= nil then
local Center = self.ParentNode.UI.Position.X.Offset --This will make it aline with the ParentNode
local AlignLeft = (#self.ParentNode.ChildArray/2)*(GuiSize.X.Offset+GapSizeX) --This will make the guis go to the farthest left node
local CorrectPosition = ((GuiSize.X.Offset+GapSizeX)*(self.Index-1)) --This will then slide the gui Right until its at the correct spot
self.UI.Position = UDim2.new(.5,(Center)-AlignLeft+CorrectPosition+(GuiSize.X.Offset+GapSizeX)/2, 0, self.ParentNode.UI.Position.Y.Offset+(GuiSize.Y.Offset+GapSizeY))
else
self.UI.Position = UDim2.new(.5, 0, 0, GuiSize.Y.Offset/2)
end
self.NodeDrawler:ConnectNodes(self.ParentNode, self)
end
function Node:AddChildNode(Node)
table.insert(self.ChildNodes, Node)
end
function Node:DrawNode()
self.UI = Instance.new("TextButton")
self.UI.Name = self.CurrentNodeObj.Name
self.UI.Text = self.Index
self.UI.Size = GuiSize
self.UI.AnchorPoint = Vector2.new(0.5, 0.5)
if self.ParentNode ~= nil then
local Center = self.ParentNode.UI.Position.X.Offset --This will make it aline with the ParentNode
local AlignLeft = (#self.ParentNode.ChildArray/2)*(GuiSize.X.Offset+GapSizeX) --This will make the guis go to the farthest left node
local CorrectPosition = ((GuiSize.X.Offset+GapSizeX)*(self.Index-1)) --This will then slide the gui Right until its at the correct spot
self.UI.Position = UDim2.new(.5,(Center)-AlignLeft+CorrectPosition+(GuiSize.X.Offset+GapSizeX)/2, 0, self.ParentNode.UI.Position.Y.Offset+(GuiSize.Y.Offset+GapSizeY))
else
self.UI.Position = UDim2.new(.5, 0, 0, GuiSize.Y.Offset/2)
end
self.UI.Parent = self.NodeDrawler.TargetFrame
self.UI.ZIndex = 2
end
return Node
heres how it currently looks