Need Help Making a Performance Based Script

{Sorry If I don’t do this right, I’m quite new to the forum}

Hello,
So I created a button script which basically iterates through a folder table of buttons and calls a MouseButton1Click event.

Here's the Sample of The Script

for i = 1, #ButtonFolder do
ButtonFolder[i].MouseButton1Click:Connect(DoStuff)
end

However, since I’m striving to make this script as performance based as possible, I tried to use the in pairs() function to iterate through the button folder and detect the script changes. Of course i wouldn’t make a local script for all the buttons in the folder, I didn’t think that was efficient at all. Then I started asking myself if these loops run directly when the client is loaded in. What actually happens with this loops? What I want to know is which type of loop should I run to detect a left mouse click on these buttons? Is there another much better way of detecting a button click event I am not aware of? Please let me know.

2 Likes

This is how I handle clicking and hovering over buttons when scripting almost every GUI I have made:

for _, button in ipairs(buttons:GetChildren()) do
	button.InputBegan:Connect(function(inputObject)
		if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
			print("clicked")
		elseif inputObject.UserInputType == Enum.UserInputType.MouseMovement then
			print("mouse enter")
		end
	end)
	button.InputEnded:Connect(function(inputObject)
		if inputObject.UserInputType == Enum.UserInputType.MouseMovement then
			print("mouse left")
		end
	end)
end

I prefer to use GuiObject.InputBegan and GuiObject.InputEnded rather than the GuiObject.MouseEnter and GuiObject.MouseLeave events as they are proven to be buggy and unreliable. Instead of using GuiButton.MouseButton1Click, I just check if the input on InputBegan was a left click, this is just because it is neater than making a separate connection and it fits in with the rest of the code.

1 Like

You can use TextButton.Activated to fire mouse click events.

1 Like

Thank you man this is a solution i’ll start employing from now on. Thank you for the feedback

I wanted to answer your question even though you already marked a solution, loops will only be expensive if your doing costly items in them, usually involving some great deal of mathematical calculation, and if they are ran excessively. For something like UI elements looping over them would not really affect performance so much, if done correctly.

I just wanted to add that how you were originally doing it is technically slightly faster than they way @RetributionVI suggested, you can read about it here on devforum https://devforum.roblox.com/t/the-art-of-micro-optimizing/226753 , in this post the persons clearly states that:

“Using ipairs on anything but LuaJIT is just dumb. It’s super, super slow. The previously mentioned numeric loop does everything it does faster (as well as in LuaJIT, but the difference is significantly reduced). If you care at all about performance, please do not use it.”
A simple google search will also confirm his argument, and also i think ipairs is the slowest way to go through a table and you would be better off using pairs.

If your wondering what LuaJIT is a faster version of Lua, but the numeric loop you had before is actually better performance-wise, although this difference isn’t very significant I wanted you to get the best answer, so the best way to do it would to be your way combined with @RetributionVI like this:

for i = 1, #ButtonFolder do
   ButtonFolder[i].InputBegan:Connect(function(inputObject)
		if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
			print("clicked")
		elseif inputObject.UserInputType == Enum.UserInputType.MouseMovement then
			print("mouse enter")
		end
	end)
	Button[i].InputEnded:Connect(function(inputObject)
		if inputObject.UserInputType == Enum.UserInputType.MouseMovement then
			print("mouse left")
		end
	end)
end

--[[
Also thought it would be worth mentioning the IsA() 
function, this can be used on any roblox instance, such
as parts, ui objects, and so on. For example to check
if an item is a Button u could do this:
if Button:IsA("TextButton") or Button:IsA("ImageButton") then
end
--just letting u know about that function
]]

here is a link to the IsA API:Instance | Documentation - Roblox Creator Hub

Just wanted to add a tip, try not to optimize to a point where your code becomes non-readable and non-maintainable in order to gain a few milliseconds of performance

4 Likes

Thanks man I needed a much more detailed and critical answer and i got it!

2 Likes

This thread is fairly outdated and should not be referenced too deeply as it is mostly applicable for the old VM. It was not created when the new VM dropped. The new VM improves performance by large margins, with ipairs seeing a significant performance increase as noted at RDC19. This criticism of theirs

is inaccurate and far too generalised. LuaU improved the performance of for iterations and ipairs has typically always been faster than pairs, as you’re comparing orderless arbitrary iteration to numeric incremental iteration. You should use ipairs not only for this reason but also because

  • It does not hamper performance: it is relatively invisible and iterations are very fast on Roblox

  • It is idiomatic and correct for array iteration, not so much a numeric for loop but it works I guess

  • Numeric for and ipairs in this scenario are running almost the exact same operation, just one involves direct incremental iteration and using the index for a table lookup (you’d need to run GetChildren; with a direct lookup, your buttons would need to have numbered names otherwise itd fail)

Be sure to also read this post as it mentions ipairs. The statement is far too generalised and ambiguous that it doesn’t provide accuracy or a good stance about the iteration matter.

https://devforum.roblox.com/t/the-art-of-micro-optimizing/226753/95?u=colbert2677

For this curious about LuaJIT: JIT is for Just-in-Time. Here’s an obligatory Wikipedia page for just-in-time compilation.

2 Likes

ipairs is faster in the new VM. That guide isn’t worth following anymore. How he had it setup was better for the new VM, but better for the old one.

Another benefit of ipairs in the new array is that localizing it should speed it up as well.

local Functions = {}

--  thought it was enabled
local function table_create(Length, Value)
	local Array = {}
	for Index = 1, Length do Array[Index] = Value end
	return Array
end

local Array = table_create(1E4, 1E4)

Functions["ipairs"] = function()
	local Clone = {}
	for Index, Value in ipairs(Array) do
		Clone[Index] = (Value + Index) / Value
	end

	Clone = nil
end

Functions["numeric"] = function()
	local Clone = {}
	for Index = 1, #Array do
		local Value = Array[Index]
		Clone[Index] = (Value + Index) / Value
	end

	Clone = nil
end

Functions["numeric knowing length"] = function()
	local Clone = {}
	for Index = 1, 1E4 do
		local Value = Array[Index]
		Clone[Index] = (Value + Index) / Value
	end

	Clone = nil
end

require(4185109675).new(1, "Array Iteration", Functions)