Smooth out in game lag when running for loop

so ive created a script that will return true if a target gui touched the gui the script is parented too.

local RunService = game:GetService("RunService")




function OnTouch(b)
	local a = b.Parent.Parent.Parent.Parent.DragableFrame
	local debounce = false
	local GuiCollisionService = require(game:GetService("ReplicatedStorage").GuiCollisionService)
	GuiCollisionService.isColliding(a, b)
	local assets = b:FindFirstChild("assets")
	if GuiCollisionService.isColliding(a,b) == true then
		b.UIStroke.Enabled = true	
		repeat wait(0.000001)
		until GuiCollisionService.isColliding(a,b) == false
		b.UIStroke.Enabled = false	
	end
end

RunService.Heartbeat:Connect(function()
	for i, b in pairs(script.Parent:GetDescendants()) do
		if b:IsA("ImageButton") then
			coroutine.wrap(OnTouch)(b)
		end
	end
end)

but when it gets to about over a good 1000 of those imagebuttons, the client starts to lag because of all those scripts in those imagebuttons.

You’re probably thinking: why not just use collectionservice? The problem with that is when all those imagebuttons are put into a table, it still lags because of the time it has to take to iterate over all of them and check if each is touching the target gui

Don’t attach demanding code to a Heartbeat function. That’s what’s causing the lag.

Also if i disable all scripts (if it was individually parented to each imagebutton) it runs smooth

If i was to have a collectionservice script instead and disable that, it also runs smoothly

This code will (on every hearbeat):

  1. Start OnTouch
  2. OnTouch requires GuiCollisionService (every time it is called) and determines if it collides.
  3. If they touched, a while-loop is started. (Side note: Anything below 0.015 won’t do any difference, and switch to task.wait() instead of wait())
  4. End loop once they stop touching

This looks, to me, like you are creating a new while loop every hearbeat.

Try switching to events the best you can, it will really ease up some performance issues. Also, move the require outside the function. You don’t need to require it every heartbeat

it didnt work. it still lags

local RunService = game:GetService("RunService")
local Collectionservice = game:GetService("CollectionService")
local GuiCollisionService = require(game:GetService("ReplicatedStorage").GuiCollisionService)



function OnTouch(b)
	local a = b.Parent.Parent.Parent.Parent.DragableFrame
	local debounce = false
	
	GuiCollisionService.isColliding(a, b)
	if GuiCollisionService.isColliding(a,b) == true then
		b.UIStroke.Enabled = true	
		repeat task.wait()
		until GuiCollisionService.isColliding(a,b) == false
		b.UIStroke.Enabled = false	
	end
end
RunService.Heartbeat:Connect(function()
	for i, b in pairs(Collectionservice:GetTagged("regions")) do
		coroutine.wrap(OnTouch)(b)
	end
end)

The main issue you got is the fact that you are doing a lot of checks every heart beat. There is no need to check regions that have not moved. To only check moved regions, use events. Quick example:

local Collectionservice = game:GetService("CollectionService")
local GuiCollisionService = require(game:GetService("ReplicatedStorage").GuiCollisionService)

function OnTouch(a, b)
	b.UIStroke.Enabled = GuiCollisionService.isColliding(a,b) -- Will be true if colliding
end

local function hookToOnTouch(obj: GuiBase) -- Makes the gui check for collision whenever it is moved/resized
	obj:GetPropertyChangedSignal("Position"):Connect(function()
		OnTouch(a, b)
	end)
	obj:GetPropertyChangedSignal("Size"):Connect(function()
		OnTouch(a, b)
	end)
end

for _, b in ipairs(Collectionservice:GetTagged("regions")) do -- change to pairs instead of ipairs if this errors
	local a = b.Parent.Parent.Parent.Parent.DragableFrame -- a will always be the same for each b (I assume? Otherwise move this back into OnTouch() )

	hookToOnTouch(a)
	hookToOnTouch(b)
end

a and b are undefined here… but thats ok because i went with a “rendering strategy” where guis would only be tagged if it is inside the player’s screen. this is how it works(in each imagebutton).

local guiInset = game:GetService("GuiService"):GetGuiInset()
local function isInScreen()
	local pos = script.Parent.AbsolutePosition + guiInset
	return pos.X + script.Parent.AbsoluteSize.X <= (game.Workspace.CurrentCamera.ViewportSize.X * 1.5) and pos.X >= 0
end

script.Parent.Changed:Connect(function(AbsolutePosition)
	isInScreen()
	if isInScreen() == true then
		tagservice:AddTag(script.Parent,"regions")
	else
		tagservice:RemoveTag(script.Parent,"regions")
	end
end)

this is why i took the “rendering” method

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.