Skip to content

Instantly share code, notes, and snippets.

@RealEthanPlayzDev
Last active February 15, 2022 13:11
Show Gist options
  • Save RealEthanPlayzDev/c4e87c5fe87297299d3a7782fccfe391 to your computer and use it in GitHub Desktop.
Save RealEthanPlayzDev/c4e87c5fe87297299d3a7782fccfe391 to your computer and use it in GitHub Desktop.
Geometry Lines Background Rendering
--[[
File name: GeometryLinesBackground.luau
Author: RadiatedExodus (ItzEthanPlayz_YT/RealEthanPlayzDev)
Created at: February 11, 2022
--]]
local serv = {
RunService = game:GetService("RunService");
Debris = game:GetService("Debris");
TweenService = game:GetService("TweenService");
}
--// This can be technically static, having one GetPropertyChangedSignal for every new object would not work well with the memory anyways
local RbxWindowSize = workspace.CurrentCamera.ViewportSize
workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
RbxWindowSize = workspace.CurrentCamera.ViewportSize
return
end)
--// Utility
local function InstanceTypeof(i: any) return if typeof(i) == "Instance" then i.ClassName else typeof(i) end
local function InvalidArgumentType(argnumber: number, funcname: string, expected: string, got: string)
return string.format("invalid argument #%d to '%s' (%s expected, got %s)", argnumber, funcname, expected, got)
end
local function GetRandomUDim2OffsetBasedOnRbxWindowSize(Rand: Random)
return UDim2.new(0, Rand:NextInteger(0, RbxWindowSize.X), 0, Rand:NextInteger(0, RbxWindowSize.Y))
end
local function CreateDot()
local dot = Instance.new("Frame")
dot.Name = "Dot"
dot.Size = UDim2.new(0, 10, 0, 10)
dot.AnchorPoint = Vector2.new(0.5, 0.5)
dot.BorderSizePixel = 0
dot.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
return dot
end
--// https://devforum.roblox.com/t/drawing-a-path-with-uis/252604/2
function drawPath(clineframe, startBtn, endBtn)
local startX, startY = startBtn.Position.X.Offset, startBtn.Position.Y.Offset
local endX, endY = endBtn.Position.X.Offset, endBtn.Position.Y.Offset
local Line = if not clineframe then Instance.new("Frame") else clineframe
Line.AnchorPoint = Vector2.new(0.5, 0.5)
Line.Size = UDim2.new(0, ((endX - startX) ^ 2 + (endY - startY) ^ 2) ^ 0.5, 0, 5) -- Get the size using the distance formula
Line.Position = UDim2.new(0, (startX + endX) / 2, 0, (startY + endY) / 2) -- Get the position using the midpoint formula
Line.Rotation = math.atan2(endY - startY, endX - startX) * (180 / math.pi) -- Get the rotation using atan2, convert radians to degrees
return Line
end
--\\
--// CLASS GeometryLinesBackground
local GeometryLinesBackground = {}
GeometryLinesBackground.__index = GeometryLinesBackground
GeometryLinesBackground.__tostring = function() return "GeometryLinesBackground" end
function GeometryLinesBackground:_GetLineFromTwoDot(fd: Frame, sd: Frame)
for index, line in ipairs(self.__lines) do
if line.FirstDot == fd and line.SecondDot == sd then
return line, index
end
end
return
end
function GeometryLinesBackground:_RandomlyTweenDotInCameraSpace(dot)
local tw = serv.TweenService:Create(dot, TweenInfo.new(6, Enum.EasingStyle.Linear), {Position = GetRandomUDim2OffsetBasedOnRbxWindowSize(self.__rand)})
tw.Completed:Connect(function()
if not self.__rendering then return end
self:_RandomlyTweenDotInCameraSpace(dot)
--// print("tweening")
end)
tw:Play()
return
end
function GeometryLinesBackground:StartRender(overridecurrentrendering: boolean?)
if not typeof(self.__rootframe) == "Instance" then return error("root frame not set", 2) end
if self.__rendering then
if overridecurrentrendering then
self:StopRender()
else
return error("already rendering, pass true to override", 2)
end
end
for i = 1, self.__amountofdots do
local dot = CreateDot()
dot.BackgroundColor3 = self.__dotbackgroundcolor3
dot.Position = GetRandomUDim2OffsetBasedOnRbxWindowSize(self.__rand)
self:_RandomlyTweenDotInCameraSpace(dot)
dot.Parent = self.__rootframe
table.insert(self.__dots, dot)
end
self.__renderevent = serv.RunService.Heartbeat:Connect(function()
for _, dot: Frame in next, self.__dots do
for _, seconddot: Frame in next, self.__dots do
if seconddot ~= dot and (dot.AbsolutePosition - seconddot.AbsolutePosition).Magnitude <= 150 then
local linedata = self:_GetLineFromTwoDot(dot, seconddot)
if not linedata then
local line = Instance.new("Frame")
line.Name = "Line"
line.BorderSizePixel = 0
line.BackgroundColor3 = self.__linebackgroundcolor3
line.Size = UDim2.new(0, 0, 0, 0)
line.Parent = self.__rootframe
linedata = {FirstDot = dot, SecondDot = seconddot, Line = line}
table.insert(self.__lines, linedata)
end
linedata.Line.BackgroundTransparency = if self.__transparencyenabled then math.clamp((dot.AbsolutePosition - seconddot.AbsolutePosition).Magnitude, 1, 150) / 150 else 0
drawPath(linedata.Line, dot, seconddot)
else
local line, index = self:_GetLineFromTwoDot(dot, seconddot)
if line then
table.remove(self.__lines, index)
serv.Debris:AddItem(line.Line, 0)
end
end
end
end
end)
self.__rendering = true
self.Rendering = true
return true
end
function GeometryLinesBackground:StopRender()
if self.__renderevent then self.__renderevent:Disconnect() end
self.__renderevent = nil
for _, line in next, self.__lines do
serv.Debris:AddItem(line.Line, 0)
end
table.clear(self.__lines)
for _, dot in next, self.__dots do
serv.Debris:AddItem(dot, 0)
end
table.clear(self.__dots)
self.__rendering = false
self.Rendering = false
return true
end
function GeometryLinesBackground:IsRendering()
return self.__rendering
end
function GeometryLinesBackground:SetAmountOfDots(newamount: number)
assert(InstanceTypeof(newamount) == "number", InvalidArgumentType(1, "SetAmountOfDots", "number", InstanceTypeof(newamount)))
assert(not self.__rendering, "attempt to set amount of dots while still rendering")
self.__amountofdots = newamount
self.AmountOfDots = newamount
return
end
function GeometryLinesBackground:SetRootFrame(newrootframe: GuiObject)
assert(InstanceTypeof(newrootframe) == "Instance", InvalidArgumentType(1, "SetRootFrame", "Instance", InstanceTypeof(newrootframe)))
assert(not self.__rendering, "attempt to set root frame while still rendering")
self.__rootframe = newrootframe
self.RootFrame = newrootframe
return
end
function GeometryLinesBackground:SetDotBackgroundColor3(newc3: Color3)
assert(InstanceTypeof(newc3) == "Color3", InvalidArgumentType(1, "SetDotBackgroundColor3", "Color3", InstanceTypeof(newc3)))
assert(not self.__rendering, "attempt to set dot color3 while still rendering")
self.__dotbackgroundcolor3 = newc3
self.DotBackgroundColor3 = newc3
return
end
function GeometryLinesBackground:SetLineBackgroundColor3(newc3: Color3)
assert(InstanceTypeof(newc3) == "Color3", InvalidArgumentType(1, "SetLineBackgroundColor3", "Color3", InstanceTypeof(newc3)))
assert(not self.__rendering, "attempt to set line color3 while still rendering")
self.__linebackgroundcolor3 = newc3
self.LineBackgroundColor3 = newc3
return
end
function GeometryLinesBackground:SetTransparencyEnabled(newtoggle: boolean)
assert(InstanceTypeof(newtoggle) == "boolean", InvalidArgumentType(1, "SetFarTransparencyEffect", "boolean", InstanceTypeof(newtoggle)))
assert(not self.__rendering, "attempt to set far transparency effect while still rendering")
self.__transparencyenabled = newtoggle
self.TransparencyEnabled = newtoggle
return
end
local function new(amountofdots: number?, rootframe: GuiObject?, randomseed: number?)
return setmetatable({
__rootframe = rootframe;
__renderevent = nil;
__rand = if randomseed then Random.new(randomseed) else Random.new();
__lines = {};
__dots = {};
__rendering = false;
__amountofdots = if typeof(amountofdots) == "number" then amountofdots else 35;
__dotbackgroundcolor3 = Color3.fromRGB(255, 255, 255);
__linebackgroundcolor3 = Color3.fromRGB(255, 255, 255);
__transparencyenabled = true;
--// Public variables
RootFrame = rootframe;
AmountOfDots = if typeof(amountofdots) == "number" then amountofdots else 35;
DotBackgroundColor3 = Color3.fromRGB(255, 255, 255);
LineBackgroundColor3 = Color3.fromRGB(255, 255, 255);
TransparencyEnabled = true;
Rendering = false;
}, GeometryLinesBackground)
end
return setmetatable({new = new}, {__call = new})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment