It’s time consuming scripting each button at a time and lengthens your script, and I’m wondering if there’s a way I can get the button the player clicked without defining each of them as a variable? (I also use typescript)
If you don’t define them, how would a script know which button is being pressed?
What you could do is have a single script for each button, but if you are looking to move your GUIs around it is better to have most or all of your GUI objects scripted in one place (ideally). Regardless, if you do this then you end up referencing the button one way or another.
I was hoping UserInputService might have some event for what you are looking for, but alas it does not (from what I know of).
You can already do this if you just reference a path to the button, like this
script.Parent.MouseButton1Click:Connect(function()
end)
That way you avoid locals in general. If the buttons are descendants then you might need to wait until they are loaded, much like you would in declaring them as variables.
This only works if all the TextButtons are children of a single parent, not multiple.
What you can do is loop through the children of their parent, and use a
if Instance:IsA('TextButton') then
line to filter through all of the GuiObjects. You will know which Button is which by doing an if statement like
if Instance.Name == 'OpenFrameButton' then
I use this method all the time because I too hate defining each TextButton when there’s many to define.
Alright, thank you for taking your time to respond. Appreciate it
If I understood your question properly, I think you mean something like this
local Plr = game:GetService("Players").LocalPlayer;
local UIS = game:GetService("UserInputService");
local PlrUI = Plr.PlayerGui;
UIS.InputBegan:Connect(function(input, processed)
if (input.UserInputType == Enum.UserInputType.MouseButton1 and processed) then
local GuiElements = PlrGUI:GetGuiObjectsAtPosition(input.Position.X, input.Position.Y);
for _,g in ipairs(GuiElements) do
if g:IsA("TextButton") or g:IsA("ImageButton") then
--<Do thingys
end
end
end
end)
will work for any device I think, and also works on buttons added late VIA scripts
Something that I use a lot is iterate over each button in a GuiElement and use a function to bind them. There’s no need to use UIS for this
local function BindButtonToFunction(btn, func)
btn.MouseButton1Click:Connect(func)
end
for _, v in pairs(GuiElement:GetChildren()) do
if v:IsA("TextButton") then
BindButtonToFuncton(btn, function()
print(btn.Name)
end)
end
end
If I used UIS, I’d have to enter the coordinates for each button, plus there are multiple pages included in the gui which would require me to do more. @FilteredDev’s solution sounds the best, binding them using a loop is much simpler and effective. Thanks for taking your time to respond.
What? you don’t need to enter each coordinate. input.Position.X
returns the position of where the input began. So since I used UserInputType.MouseButton
, It’ll return the mouses position. Equivalent to using Mouse.X, Mouse.Y
.
I wasn’t sure if it would work for UI elements which are using scale. And does it only apply to elements which are visible, or all of them, regardless of them being visible or not? Because I have multiple UIs overlaying each other.
It’ll apply to any TextButton
or ImageButton
You can check if it’s visible by saying
UIS.InputBegan:Connect(function(input, processed)
if (input.UserInputType == Enum.UserInputType.MouseButton1 and processed) then
local GuiElements = PlrGUI:GetGuiObjectsAtPosition(input.Position.X, input.Position.Y);
for _,g in ipairs(GuiElements) do
if g:IsA("TextButton") or g:IsA("ImageButton") then
if(g.Visible == true) then
--< I usually use an ignore list
end;
end
end
end
end)
Alrighty, thank you for helping, I’ll give it a try
I have an event based approach for doing this if I understand this correctly.
--On a module script
local player = game:GetService("Players").Local player
local module = {OnGlobalClick = {}}
function module.OnGlobalClick:Connect(func)
for _, gui in pairs(player.PlayerGui:GetDescendants()) do
if gui:IsA("TextButton") or gui:IsA("ImageButton") then
gui.MouseButton1Click:Connect(function()
func(gui)
end)
end
end
player.PlayerGui.DescendantAdded:Connect(function(desc)
if desc:IsA("TextButton") or desc:IsA("ImageButton") then
desc.MouseButton1Click:Connect(function()
func(desc)
end)
end
end)
end
return module
Then you could have a local script
local module = require(theModule)
module.OnGlobalClick:Connect(function(buttonThatWasClicked)
print(buttonThatWasClicked.Name.." was clicked")
end)
This will add a new connection to all present clickable guis aswell as newly added ones. This can be used in any local script that is able to access the module.
Note: This code can be optimized in the way you want
This might not be very convenient for a single operation such as this, but when you have multiple utilities like this, I would prefer a module.