I’m trying to color connecting walls to match as they get created. Basically, I have nodes on a grid, grouped together
I generate line segments between A-B
as you can see each line generates a left and right line. I want to calculate that its connecting at a node, and calculate the connecting lines, to color them accordingly. My code atm just colors the same segments together (I don’t want that)
This is what it SHOULD look like
local Nodes = workspace:WaitForChild("Nodes")
local WALL_OFFSET = 0.45
local WALL_THICKNESS = 0.05
local WALL_HEIGHT = 14
-- Global state for unique coloring
local globalColorIndex = 1
local function VecKey(vec)
return string.format("%.3f,%.3f", vec.X, vec.Z)
end
local function CreateWallPart(startPos, endPos, sideOffset, name)
local Direction = (endPos - startPos)
local Length = Direction.Magnitude
local MidPoint = (startPos + endPos) / 2
local LookCFrame = CFrame.lookAt(MidPoint, endPos, Vector3.yAxis)
local Offset = LookCFrame.RightVector * sideOffset
local Part = Instance.new("Part")
Part.Name = name
Part.Size = Vector3.new(WALL_THICKNESS, WALL_HEIGHT, Length)
Part.Anchored = true
Part.CanCollide = true
Part.TopSurface = Enum.SurfaceType.Smooth
Part.BottomSurface = Enum.SurfaceType.Smooth
Part.CFrame = LookCFrame + Offset
return Part, LookCFrame.LookVector, Offset
end
local function SignedAngle2D(a: Vector3, b: Vector3): number
local dot = a.X * b.X + a.Z * b.Z
local det = a.X * b.Z - a.Z * b.X
return math.deg(math.atan2(det, dot))
end
local function GetUniqueColor(index)
local palette = {
Color3.fromRGB(255, 0, 0), Color3.fromRGB(0, 0, 255), Color3.fromRGB(0, 255, 0),
Color3.fromRGB(255, 255, 0), Color3.fromRGB(255, 0, 255), Color3.fromRGB(0, 255, 255),
Color3.fromRGB(128, 0, 128), Color3.fromRGB(255, 165, 0), Color3.fromRGB(165, 42, 42),
Color3.fromRGB(75, 0, 130)
}
return palette[(index - 1) % #palette + 1]
end
local Segments = {}
local NodeConnections = {}
local function AddToNodeMap(key, segment)
NodeConnections[key] = NodeConnections[key] or {}
table.insert(NodeConnections[key], segment)
end
local PartToColorIndex = {}
local ColorIndexToColor = {}
local function TryAssignColorToPart(part, nodeKey, basePos)
local dir = (part.Position - basePos).Unit
local angle = math.atan2(dir.Z, dir.X)
local bestMatch = nil
local bestAngleDiff = math.huge
local connections = NodeConnections[nodeKey]
if not connections then return end
for _, seg in ipairs(connections) do
local candidates = {seg.Left, seg.Right}
for _, otherPart in ipairs(candidates) do
if otherPart == part then continue end
if not otherPart:IsDescendantOf(workspace) then continue end
local otherBase = (seg.StartKey == nodeKey) and seg.StartPos or seg.EndPos
local otherDir = (otherPart.Position - otherBase).Unit
local otherAngle = math.atan2(otherDir.Z, otherDir.X)
local diff = math.abs(math.atan2(math.sin(angle - otherAngle), math.cos(angle - otherAngle)))
if diff < bestAngleDiff then
bestAngleDiff = diff
bestMatch = otherPart
end
end
end
if bestMatch and PartToColorIndex[bestMatch] then
local colorIndex = PartToColorIndex[bestMatch]
part.Color = ColorIndexToColor[colorIndex]
PartToColorIndex[part] = colorIndex
else
-- New color
local newIndex = globalColorIndex
globalColorIndex += 1
local color = GetUniqueColor(newIndex)
part.Color = color
PartToColorIndex[part] = newIndex
ColorIndexToColor[newIndex] = color
end
end
for _, Node in ipairs(Nodes:GetChildren()) do
local A = Node:FindFirstChild("A")
local B = Node:FindFirstChild("B")
if not (A and B and A:IsA("BasePart") and B:IsA("BasePart")) then continue end
local APos, BPos = A.Position, B.Position
local AKey, BKey = VecKey(APos), VecKey(BPos)
local Dir = (BPos - APos).Unit
local WallModel = Instance.new("Model")
WallModel.Name = Node.Name .. "_Wall"
WallModel.Parent = Node
local Left, _, _ = CreateWallPart(APos, BPos, -WALL_OFFSET / 2, "Left")
local Right, _, _ = CreateWallPart(APos, BPos, WALL_OFFSET / 2, "Right")
Left.Parent = WallModel
Right.Parent = WallModel
local Segment = {
StartPos = APos,
EndPos = BPos,
StartKey = AKey,
EndKey = BKey,
Dir = Dir,
Left = Left,
Right = Right,
Model = WallModel,
}
table.insert(Segments, Segment)
AddToNodeMap(AKey, Segment)
AddToNodeMap(BKey, Segment)
TryAssignColorToPart(Left, AKey, APos)
TryAssignColorToPart(Right, BKey, BPos)
task.wait()
end