Hello there
GuiManager2d is a module that helps making 2d Gui code less of a nightmare. Everything is based on scale instead of offset so it works on every screen size and shape!
Current Version [v1.4]:
v1.4 Summary
-
Added Destroying connection to clear GuiManager2d classes from gui that is destroyed externally
-
Added
DisableGlobalEventParams
,DisableLocalEventParams
andDisableDestroyConnection
settings -
Added GuiBase2d check for
GuiManager2d.new()
-
Couple of internal changes
)
Showcase and Samples
This video shows what GuiManager is currently capable of by just using some of it’s functions. The video also displays that everything is scaled when the window is made smaller, so it works just fine on any sized screen.
Local Script used in the video
local localPlayer = game:GetService("Players").LocalPlayer
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local GuiManager2d = require(ReplicatedStorage:WaitForChild("GuiManager2d"))
local screenGui = Instance.new("ScreenGui", localPlayer.PlayerGui)
local ui = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "Click and Drag Me!",
Position = UDim2.fromScale(0.9, 0.75),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "Click and Drag Me!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui2 = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "Click and Rotate Me!",
Position = UDim2.fromScale(0.9, 0.25),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "Click and Rotate Me!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui3 = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "I'm Tweening!",
Position = UDim2.fromScale(0.1, 0.25),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "I'm Tweening!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui4 = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "I'm being Set!",
Position = UDim2.fromScale(0.05, 0.75),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "I'm being Set!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui5 = GuiManager2d.new("Frame", {
Parent = screenGui,
Name = "Background",
Transparency = 0.5,
Position = UDim2.fromScale(0.5, 0.5),
Size = UDim2.fromScale(0.45, 0.45),
AnchorPoint = Vector2.new(0.5, 0.5)
})
local ui6 = GuiManager2d.new("TextLabel", {
Parent = ui5.Ui,
Name = "Drag me downwards!",
Position = UDim2.fromScale(0, 0),
Size = UDim2.fromScale(0.25, 0.25),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundColor3 = Color3.fromRGB(65, 65, 65),
TextColor3 = Color3.new(1, 1, 1),
Text = "Drag me downwards!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui7 = GuiManager2d.new("TextLabel", {
Parent = ui5.Ui,
Name = "Drag me sideways, I snap in place!",
Position = UDim2.fromScale(0, 1),
Size = UDim2.fromScale(0.25, 0.25),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundColor3 = Color3.fromRGB(65, 65, 65),
TextColor3 = Color3.new(1, 1, 1),
Text = "Drag me sideways, I snap in place!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui8 = GuiManager2d.new("TextLabel", {
Parent = ui5.Ui,
Name = "Drag me, I snap to a grid!",
Position = UDim2.fromScale(0.35, 0.5),
Size = UDim2.fromScale(0.25, 0.25),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundColor3 = Color3.fromRGB(65, 65, 65),
TextColor3 = Color3.new(1, 1, 1),
Text = "Drag me, I snap to a grid!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui9 = GuiManager2d.new("TextLabel", {
Parent = ui5.Ui,
Name = "Rotate me, I snap in place and only go to 180 degrees!",
Position = UDim2.fromScale(0.65, 0.5),
Size = UDim2.fromScale(0.25, 0.25),
AnchorPoint = Vector2.new(0.5, 0.5),
BackgroundColor3 = Color3.fromRGB(65, 65, 65),
TextColor3 = Color3.new(1, 1, 1),
Text = "Rotate me, I snap in place and only go to 180 degrees!",
Font = Enum.Font.Code,
TextScaled = true
})
local ui10 = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "Currently not Overlapping",
Position = UDim2.fromScale(0.35, 0.9),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "Currently not Overlapping",
Font = Enum.Font.Code,
TextScaled = true
})
local ui11 = GuiManager2d.new("TextLabel", {
Parent = screenGui,
Name = "Currently not Overlapping",
Position = UDim2.fromScale(0.65, 0.9),
Size = UDim2.fromScale(0.15, 0.15),
AnchorPoint = Vector2.new(0.5, 0.5),
Text = "Currently not Overlapping",
Font = Enum.Font.Code,
TextScaled = true
})
ui:Draggable()
ui.DraggingChanged:Connect(function(difference: UDim2)
print("Position Difference:", difference)
ui:Overlap(screenGui:GetDescendants())
end)
ui.DraggingEnded:Connect(function(difference: UDim2)
warn("Final Position Difference:", difference)
end)
ui2:Rotatable()
ui2.RotatingChanged:Connect(function(difference: number)
print("Rotation Difference:", difference)
end)
ui2.RotatingEnded:Connect(function(difference: number)
warn("Final Rotation Difference:", difference)
end)
ui3:Tween({
Position = UDim2.fromScale(0.1, 0.5),
BackgroundColor3 = Color3.fromRGB(160, 160, 0),
Rotation = 360
}, TweenInfo.new(1, Enum.EasingStyle.Sine, Enum.EasingDirection.In, -1, true))
task.spawn(function()
while task.wait() do
ui4:Set({
Position = UDim2.fromScale(0.05, 0.75),
BackgroundColor3 = Color3.fromRGB(160, 0, 0),
Size = UDim2.fromScale(0.05, 0.05)
})
task.wait(1)
ui4:Set({
Position = UDim2.fromScale(0.075, 0.75),
BackgroundColor3 = Color3.fromRGB(0, 160, 0),
Size = UDim2.fromScale(0.1, 0.1)
})
task.wait(1)
ui4:Set({
Position = UDim2.fromScale(0.1, 0.75),
BackgroundColor3 = Color3.fromRGB(0, 0, 160),
Size = UDim2.fromScale(0.15, 0.15)
})
task.wait(1)
end
end)
ui6:Draggable({
X = Vector2.new(0, 0),
Y = Vector2.new(0, 1)
})
ui6.DraggingChanged:Connect(function(difference: UDim2)
print("Position Difference:", difference)
end)
ui6.DraggingEnded:Connect(function(difference: UDim2)
warn("Final Position Difference:", difference)
end)
ui7:Draggable({
X = Vector2.new(0, 1),
Y = Vector2.new(1, 1)
},
{
X = 0.1
})
ui7.DraggingChanged:Connect(function(difference: UDim2)
print("Position Difference:", difference)
end)
ui7.DraggingEnded:Connect(function(difference: UDim2)
warn("Final Position Difference:", difference)
end)
ui8:Draggable({
X = Vector2.new(0.15, 0.85),
Y = Vector2.new(0.15, 0.85)
},
{
X = 0.1,
Y = 0.1
})
ui8.DraggingChanged:Connect(function(difference: UDim2)
print("Position Difference:", difference)
end)
ui8.DraggingEnded:Connect(function(difference: UDim2)
warn("Final Position Difference:", difference)
end)
ui9:Rotatable({
X = Vector2.new(0, 180)
},
{
X = 30
})
ui9.RotatingChanged:Connect(function(difference: number)
print("Rotation Difference:", difference)
end)
ui9.RotatingEnded:Connect(function(difference: number)
warn("Final Rotation Difference:", difference)
end)
task.spawn(function()
while task.wait(1) do
ui10:Set({
Position = UDim2.fromScale(0.45, 0.9)
})
ui11:Set({
Position = UDim2.fromScale(0.55, 0.9)
})
local overlapResult = ui10:Overlap({ui11.Ui})
if overlapResult and table.find(overlapResult, ui11.Ui) then
ui10:Set({
Text = "We're Overlapping!"
})
ui11:Set({
Text = "We're Overlapping!"
})
end
task.wait(1)
ui10:Set({
Position = UDim2.fromScale(0.35, 0.9),
Text = "Currently Not Overlapping"
})
ui11:Set({
Position = UDim2.fromScale(0.65, 0.9),
Text = "Currently Not Overlapping"
})
end
end)
-
gui.new()
was used to make the ui elements. The first parameter is the type of ui element you want to create, the second parameter is a table of properties to apply (The parent property is always set last despite its position in the table).gui.setup()
can be used on already existing ui elements. -
gui:Tween()
is a function that is used on the table returned bygui.new()
, and is basically a wrapper for TweenService:Create(), but the first parameter is filled in by the ui element and automatically played. The first parameter of this function is the goal, and the second is the TweenInfo. -
gui:Change()
is a function that is also used on the table returned by gui.new(), and just sets the property to those passed in the first parameter as a table. -
ui:Draggable()
is once again a function that is used on the table returned bygui.new()
, and is what enables the draggable functionality of the ui. The first parameter is a table containing two Vector2’s for the X and Y axis, these values act as clamps so things like sliders can be made. The second parameter is a table containing two numbers for the X and Y axis, these values determine what the values should be rounded to, allowing snapping and grids to be made. IfOnlyOnEnded
is set to true in either of these tables, the clamping / gridding will only be applied when the mouse button is lifted. -
ui:Rotatable()
as you guessed is a function that is used on the table returned bygui.new()
, and is what enables the rotatability of the ui. The first parameter is a Vector2 value which acts as a clamp for rotation. The second parameter is a number and causes the ui to rotate in segments (e.g. only 30 degrees at a time). The third parameter is theOnlyOnEnded
boolean and behaves the same as inui:Draggable()
)
Sources
Module Model: GuiManager2d - Roblox
Module Demo (Uncopylocked): GuiManager2d Demo - Roblox
Module Code
--!strict
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")
local PlayerGui = game:GetService("Players").LocalPlayer.PlayerGui
local GoodSignal = require(script:WaitForChild("GoodSignal"))
local defaultInfo = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
type setting = "DisableGlobalEvents"
| "DisableGlobalEventParams"
| "DisableLocalEvents"
| "DisableLocalEventParams"
| "DisableAttributes"
| "DisableDestroyConnection"
type clamp1D = {
X: Vector2?,
OnlyOnEnded: boolean?
}
type grid1D = {
X: number?,
OnlyOnEnded: boolean?
}
type clamp2D = {
X: Vector2?,
Y: Vector2?,
OnlyOnEnded: boolean?
}
type grid2D = {
X: number?,
Y: number?,
OnlyOnEnded: boolean?
}
type array = {[number]: any?}
type dictionary = {[any]: any?}
local Settings = {
DisableGlobalEvents = false,
DisableGlobalEventParams = false,
DisableLocalEvents = false,
DisableLocalEventParams = false,
DisableAttributes = false,
DisableDestroyConnection = false
}
local GuiManager2d = {}
GuiManager2d.__index = GuiManager2d
GuiManager2d.DraggingBegan = GoodSignal.new()
GuiManager2d.DraggingChanged = GoodSignal.new()
GuiManager2d.DraggingEnded = GoodSignal.new()
GuiManager2d.RotatingBegan = GoodSignal.new()
GuiManager2d.RotatingChanged = GoodSignal.new()
GuiManager2d.RotatingEnded = GoodSignal.new()
local function round(number: number, bound: number): number
return math.round(number / bound) * bound
end
local function metaSetup(ui: GuiBase2d): any
assert(typeof(ui) == "Instance" and ui:IsA("GuiBase2d"), "ui must be a GuiBase2d")
return setmetatable({
["Ui"] = ui,
["Connections"] = {},
["DraggingBegan"] = GoodSignal.new(),
["DraggingChanged"] = GoodSignal.new(),
["DraggingEnded"] = GoodSignal.new(),
["RotatingBegan"] = GoodSignal.new(),
["RotatingChanged"] = GoodSignal.new(),
["RotatingEnded"] = GoodSignal.new()
}, GuiManager2d)
end
function GuiManager2d.new(name: string, properties: dictionary): dictionary
local ui = Instance.new(name)
local parent = nil
assert(ui:IsA("GuiBase2d"), "ui must be a GuiBase2d")
for prop, value in pairs(properties) do
if (prop == "Parent") then parent = value continue end
ui[prop] = value
end
ui.Parent = parent
local class = metaSetup(ui)
if not Settings.DisableDestroyConnection then
ui.Destroying:Once(function()
class:Clear()
end)
end
return class
end
function GuiManager2d.setup(ui: GuiBase2d): dictionary
assert(typeof(ui) == "Instance" and ui:IsA("GuiBase2d"), "ui must be a GuiBase2d")
local class = metaSetup(ui)
if not Settings.DisableDestroyConnection then
ui.Destroying:Once(function()
class:Clear()
end)
end
return class
end
function GuiManager2d.updateSettings(option: setting, value: any)
Settings[option] = value
end
function GuiManager2d:Tween(goal: dictionary, tweenInfo: TweenInfo?)
TweenService:Create(self.Ui, (tweenInfo or defaultInfo), goal):Play()
end
function GuiManager2d:TweenChildren(goal: dictionary, tweenInfo: TweenInfo?, recursive: boolean?)
local uis = if recursive then self.Ui:GetDescendants() else self.Ui:GetChildren()
table.insert(uis, self.Ui)
for _, ui in ipairs(uis) do
TweenService:Create(ui, (tweenInfo or defaultInfo), goal):Play()
end
end
function GuiManager2d:Set(goal: dictionary)
for prop, value in pairs(goal) do
self.Ui[prop] = value
end
end
function GuiManager2d:SetChildren(goal: dictionary, recursive: boolean?)
local uis = if recursive then self.Ui:GetDescendants() else self.Ui:GetChildren()
table.insert(uis, self.Ui)
for _, ui in ipairs(uis) do
for prop, value in pairs(goal) do
ui[prop] = value
end
end
end
function GuiManager2d:Destroy()
self.Ui:Destroy()
for _, conn in pairs(self.Connections) do
if conn.Connected then conn:Disconnect() end
end
for _, signal in pairs(self) do
if (type(signal) ~= "table") or (signal["DisconnectAll"] == nil) then continue end
signal:DisconnectAll()
end
table.clear(self)
end
function GuiManager2d:Clear(): Instance
local ui = self.Ui
for _, conn in pairs(self.Connections) do
if conn.Connected then conn:Disconnect() end
end
for _, signal in pairs(self) do
if (type(signal) ~= "table") or (signal["DisconnectAll"] == nil) then continue end
signal:DisconnectAll()
end
table.clear(self)
return ui
end
function GuiManager2d:Draggable(clamp: clamp2D?, grid: grid2D?)
assert(typeof(self.Ui.Parent) == "Instance" and self.Ui.Parent:IsA("GuiBase2d"), "The Ui's parent must be a GuiBase2d")
assert(self.Connections.RotatingChanged == nil, "Rotation must be disabled before Dragging can be enabled")
local draggingConn = self.Connections.DraggingChanged
if draggingConn then
if (self.Connections.DraggingBegan and self.Connections.DraggingBegan.Connected) then self.Connections.DraggingBegan:Disconnect() end
if (self.Connections.DraggingChanged and self.Connections.DraggingChanged.Connected) then self.Connections.DraggingChanged:Disconnect() end
if (self.Connections.DraggingEnded and self.Connections.DraggingEnded.Connected) then self.Connections.DraggingEnded:Disconnect() end
self.Connections.DraggingBegan = nil
self.Connections.DraggingChanged = nil
self.Connections.DraggingEnded = nil
else
local dragging = false
local startingPosition: UDim2
self.Connections.DraggingBegan = self.Ui.InputBegan:Connect(function(input: InputObject)
if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
dragging = true
startingPosition = self.Ui.Position
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
if not Settings.DisableGlobalEvents then GuiManager2d.DraggingBegan:Fire(globalSelf) end
if not Settings.DisableLocalEvents then self.DraggingBegan:Fire() end
if not Settings.DisableAttributes then self.Ui:SetAttribute("Dragging", true) end
end
end)
self.Connections.DraggingChanged = UserInputService.InputChanged:Connect(function(input: InputObject, gp: boolean)
if dragging and not gp and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
local absolutePos = self.Ui.Parent.AbsolutePosition
local mousePos = Vector2.new(input.Position.X - absolutePos.X, input.Position.Y - absolutePos.Y)
local unit = (mousePos / self.Ui.Parent.AbsoluteSize)
local scale = UDim2.fromScale(math.clamp(unit.X, 0, 1), math.clamp(unit.Y, 0, 1))
local roundX = if (grid and grid.X) then round(scale.X.Scale, grid.X) else scale.X.Scale
local roundY = if (grid and grid.Y) then round(scale.Y.Scale, grid.Y) else scale.Y.Scale
scale = if (grid and not grid.OnlyOnEnded) then UDim2.fromScale(roundX, roundY) else scale
local clampX = if (clamp and clamp.X) then math.clamp(scale.X.Scale, clamp.X.X, clamp.X.Y) else scale.X.Scale
local clampY = if (clamp and clamp.Y) then math.clamp(scale.Y.Scale, clamp.Y.X, clamp.Y.Y) else scale.Y.Scale
scale = if (clamp and not clamp.OnlyOnEnded) then UDim2.fromScale(clampX, clampY) else scale
local posDifference = UDim2.fromScale(
(self.Ui.Position.X.Scale - scale.X.Scale),
(self.Ui.Position.Y.Scale - scale.Y.Scale)
)
self.Ui.Position = scale
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
local globalDiff = if not Settings.DisableGlobalEventParams then posDifference else nil
local localDiff = if not Settings.DisableLocalEventParams then posDifference else nil
if not Settings.DisableGlobalEvents then GuiManager2d.DraggingChanged:Fire(globalSelf, globalDiff) end
if not Settings.DisableLocalEvents then self.DraggingChanged:Fire(localDiff) end
end
end)
self.Connections.DraggingEnded = self.Ui.InputEnded:Connect(function(input: InputObject)
if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
dragging = false
local absolutePos = self.Ui.Parent.AbsolutePosition
local mousePos = Vector2.new(input.Position.X - absolutePos.X, input.Position.Y - absolutePos.Y)
local unit = (mousePos / self.Ui.Parent.AbsoluteSize)
local scale = UDim2.fromScale(math.clamp(unit.X, 0, 1), math.clamp(unit.Y, 0, 1))
local roundX = if (grid and grid.X) then round(scale.X.Scale, grid.X) else scale.X.Scale
local roundY = if (grid and grid.Y) then round(scale.Y.Scale, grid.Y) else scale.Y.Scale
scale = if grid then UDim2.fromScale(roundX, roundY) else scale
local clampX = if (clamp and clamp.X) then math.clamp(scale.X.Scale, clamp.X.X, clamp.X.Y) else scale.X.Scale
local clampY = if (clamp and clamp.Y) then math.clamp(scale.Y.Scale, clamp.Y.X, clamp.Y.Y) else scale.Y.Scale
scale = if clamp then UDim2.fromScale(clampX, clampY) else scale
local posDifference = UDim2.fromScale(
(self.Ui.Position.X.Scale - startingPosition.X.Scale),
(self.Ui.Position.Y.Scale - startingPosition.Y.Scale)
)
self.Ui.Position = scale
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
local globalDiff = if not Settings.DisableGlobalEventParams then posDifference else nil
local localDiff = if not Settings.DisableLocalEventParams then posDifference else nil
if not Settings.DisableGlobalEvents then GuiManager2d.DraggingEnded:Fire(globalSelf, globalDiff) end
if not Settings.DisableLocalEvents then self.DraggingEnded:Fire(localDiff) end
if not Settings.DisableAttributes then self.Ui:SetAttribute("Dragging", false) end
end
end)
end
end
function GuiManager2d:Rotatable(clamp: clamp1D?, grid: grid1D?)
assert(typeof(self.Ui.Parent) == "Instance" and self.Ui.Parent:IsA("GuiBase2d"), "The Ui's parent must be a GuiBase2d")
assert(self.Connections.DraggingChanged == nil, "Dragging must be disabled before Rotation can be enabled")
local screenGui = self.Ui:FindFirstAncestorWhichIsA("ScreenGui")
assert(screenGui, "The Ui must have a ScreenGui as an ancestor")
local rotatingConn = self.Connections.RotatingChanged
if rotatingConn then
if (self.Connections.RotatingBegan and self.Connections.RotatingBegan.Connected) then self.Connections.RotatingBegan:Disconnect() end
if (self.Connections.RotatingChanged and self.Connections.RotatingChanged.Connected) then self.Connections.RotatingChanged:Disconnect() end
if (self.Connections.RotatingEnded and self.Connections.RotatingEnded.Connected) then self.Connections.RotatingEnded:Disconnect() end
self.Connections.RotatingBegan = nil
self.Connections.RotatingChanged = nil
self.Connections.RotatingEnded = nil
else
local rotating = false
local startingRotation: number
self.Connections.RotatingBegan = self.Ui.InputBegan:Connect(function(input: InputObject)
if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
rotating = true
startingRotation = self.Ui.Rotation
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
if not Settings.DisableGlobalEvents then GuiManager2d.RotatingBegan:Fire(globalSelf) end
if not Settings.DisableLocalEvents then self.RotatingBegan:Fire() end
if not Settings.DisableAttributes then self.Ui:SetAttribute("Rotating", true) end
end
end)
self.Connections.RotatingChanged = UserInputService.InputChanged:Connect(function(input: InputObject, gp: boolean)
if rotating and not gp and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
local absolutePos = screenGui.AbsolutePosition
local mousePos = Vector2.new(input.Position.X - absolutePos.X, input.Position.Y - absolutePos.Y)
local center = self.Ui.AbsolutePosition + (self.Ui.AbsoluteSize / 2)
local rotation = math.deg(math.atan2(mousePos.Y - center.Y, mousePos.X - center.X))
rotation = if (grid and grid.X and not grid.OnlyOnEnded) then round(rotation, grid.X) else rotation
rotation = if (clamp and clamp.X and not clamp.OnlyOnEnded) then math.clamp(rotation, clamp.X.X, clamp.X.Y) else rotation
local rotateDifference = (self.Ui.Rotation - rotation)
self.Ui.Rotation = rotation
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
local globalDiff = if not Settings.DisableGlobalEventParams then rotateDifference else nil
local localDiff = if not Settings.DisableLocalEventParams then rotateDifference else nil
if not Settings.DisableGlobalEvents then GuiManager2d.RotatingChanged:Fire(globalSelf, globalDiff) end
if not Settings.DisableLocalEvents then self.RotatingChanged:Fire(localDiff) end
end
end)
self.Connections.RotatingEnded = self.Ui.InputEnded:Connect(function(input: InputObject)
if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
rotating = false
local absolutePos = screenGui.AbsolutePosition
local mousePos = Vector2.new(input.Position.X - absolutePos.X, input.Position.Y - absolutePos.Y)
local center = self.Ui.AbsolutePosition + (self.Ui.AbsoluteSize / 2)
local rotation = math.deg(math.atan2(mousePos.Y - center.Y, mousePos.X - center.X))
rotation = if (grid and grid.X) then round(rotation, grid.X) else rotation
rotation = if (clamp and clamp.X) then math.clamp(rotation, clamp.X.X, clamp.X.Y) else rotation
local rotateDifference = (self.Ui.Rotation - startingRotation)
self.Ui.Rotation = rotation
local globalSelf = if not Settings.DisableGlobalEventParams then self else nil
local globalDiff = if not Settings.DisableGlobalEventParams then rotateDifference else nil
local localDiff = if not Settings.DisableLocalEventParams then rotateDifference else nil
if not Settings.DisableGlobalEvents then GuiManager2d.RotatingEnded:Fire(globalSelf, globalDiff) end
if not Settings.DisableLocalEvents then self.RotatingEnded:Fire(localDiff) end
if not Settings.DisableAttributes then self.Ui:SetAttribute("Rotating", false) end
end
end)
end
end
function GuiManager2d:Overlap(toSearch: {Instance}, filterList: {GuiBase2d}?, filterType: ("Blacklist" | "Whitelist")?): {GuiBase2d}
local overlapResult: {GuiBase2d} = {}
local selfTopLeftCorner = self.Ui.AbsolutePosition
local selfBottomRightCorner = (self.Ui.AbsolutePosition + self.Ui.AbsoluteSize)
for _, object in ipairs(toSearch) do
if (object ~= self.Ui) and object:IsA("GuiBase2d") then
if (filterList ~= nil and filterType == "Blacklist") and table.find(filterList, object) then continue end
if (filterList ~= nil and filterType == "Whitelist") and not table.find(filterList, object) then continue end
local objectTopLeftCorner = object.AbsolutePosition
local objectBottomRightCorner = (object.AbsolutePosition + object.AbsoluteSize)
if (selfTopLeftCorner.X > objectBottomRightCorner.X) or (objectTopLeftCorner.X > selfBottomRightCorner.X) then continue end
if (selfTopLeftCorner.Y > objectBottomRightCorner.Y) or (objectTopLeftCorner.Y > selfBottomRightCorner.Y) then continue end
table.insert(overlapResult, object)
end
end
return overlapResult
end
return GuiManager2d
--[[
Made by M_dgettMann (@shadowflame63)
GuiManager [v1.4]
How to use each basic function:
GuiManager2d.new(name, properties) -- Creates the named ui, sets it properties (parents last) and sets up the metatable
GuiManager2d.setup(ui) -- Sets up a metatable so all these functions can be used on the passed ui Instance
GuiManager2d.updateSettings(setting, value) -- Sets the passed setting to the passed value
GuiManager2d:Tween(goal, tweenInfo) -- Tween the values of the given properties inside goal
GuiManager2d:TweenChildren(goal, tweenInfo, recursive) -- Same as Tween, but includes children (or descendants if recursive is true)
GuiManager2d:Set(goal) -- Sets the values of the given properties inside goal, without tweening
GuiManager2d:SetChildren(goal, recursive) -- Same as Set, but includes children (or descendants if recursive is true)
GuiManager2d:Destroy() -- Destroys the ui and clears its associated table
GuiManager2d:Clear() -- Clears the ui's associated table without destroying the ui itself, returns ui Instance
How to use each advanced function:
GuiManager2d:Draggable(clamp -> { -- Allows ui to be draggable, clamps and grids can be setup to make things like sliders and inventories
X = Vector2.new(min, max),
Y = Vector2.new(min, max),
OnlyOnEnded = boolean
},
grid -> {
X = number,
Y = number,
OnlyOnEnded = boolean
})
GuiManager2d:Rotatable(clamp -> { -- Allows ui to be rotated via dragging, a clamp and grid can be setup
X = Vector2.new(min, max),
OnlyOnEnded = boolean
},
grid -> {
X = number,
OnlyOnEnded = boolean
})
GuiManager2d:Overlap(toSearch -> {Instance}, -- Returns an array of ui overlapping the original one, if they are in the 'toSearch' table
filterList -> {GuiBase2d},
filterType -> "Blacklist" or "Whitelist"
)
How to use the global events:
GuiManager2d.DraggingBegan:Connect(function(ui, difference) -- All ui fire this event, useful for knowing everything that is active in one go
print(ui) -- Prints the table that contains the Ui, it's active Connections and the ScreenGui it's under
print(difference) -- Prints the difference in Position of the Ui, as a Udim2 value
end)
> This example applies for DraggingBegan, DraggingChanged, DraggingEnded, RotatingBegan, RotatingChanged and RotatingEnded
> These events can be disabled by setting 'Gui.DisableGlobalEvents' to true
How to use the local events:
ui.DraggingBegan:Connect(function(difference) -- Only the ui that was used to call the event fires it, so the only parameter is difference
print(difference) -- Prints the difference in Position of the Ui, as a Udim2 value
end)
> This example applies for DraggingBegan, DraggingChanged, DraggingEnded, RotatingBegan, RotatingChanged and RotatingEnded
> These events can be disabled by setting 'Gui.DisableLocalEvents' to true
How Settings work:
GuiManager2d.updateSettings(setting, value) -- Changes the passed setting to the passed value
> DisableGlobalEvents -> When true, all global bindable events associated with gui won't fire
> DisableGlobalEventParams -> When true, all global events won't pass any parameters along
> DisableLocalEvents -> When true, all local bindable events associated with gui won't fire
> DisableGlobalEventParams -> When true, all local events won't pass any parameters along
> DisableAttributes -> When true, all attributes made by this module won't be set on gui
> DisableDestroyingConnection -> When true, the Destroying connection won't be made (Only enable this if you're certain Gui won't be destroyed externally)
]]
Thanks for checking this post out and I hope you enjoy this resource! I plan to update it within the foreseeable future, I also plan to make GuiManager3d, GuiUtilities, GuiEffects and GuiAnimator as separate modules at some point.
If you have any ideas or bug reports, reply to this post or message me!