For loop in run service. Bad Practice?

is it ever ok to do something like this? or is this a better solution

local RunService = game:GetService("RunService")
local Collectionservice = game:GetService("CollectionService")
local play = game.ReplicatedStorage.Events.Playsound2
local stop = game.ReplicatedStorage.Events.StopSound

function OnTouch(b)

	if a.AbsolutePosition.X >= b.AbsolutePosition.X and a.AbsolutePosition.X <= b.AbsolutePosition.X+b.AbsoluteSize.X then
		
		if b.UIStroke.Enabled == true then return end
		local velocity = b.assets.Velocity.Value
		b.UIStroke.Enabled = true
	else
		b.UIStroke.Enabled = false
	end

end



RunService.RenderStepped:Connect(function()
	local data = game.CollectionService:GetTagged("regions")
	for i = 1,#data do local v = data[i]

		coroutine.wrap(OnTouch)(v)
	end
end)

especially when collection service tags reach ~700?
its gets laggy

they do get removed ever so often

the script takes ~32% of my memory

2 Likes
  1. Use a global array instead of running GetTagged everytime. Most of the memory usage is very likely coming from creating a new table every frame. This could look like:
local RegionList = CollectionService:GetTagged("Region")

local function OnRegionAdded(Object)
	table.insert(RegionList, Object)
end

local function OnRegionRemoved(Object)
	table.remove(RegionList, table.find(RegionList, Object))
end

CollectionService:GetInstanceAddedSignal("Region"):Connect(OnRegionAdded)
CollectionService:GetInstanceRemovedSignal("Region"):Connect(OnRegionRemoved)
  1. I would say to use RunService:BindToRenderStep, as you can control in what order the callback is ran in relation to other engine loops. For example, since your regions are checking for GUI state, you can bind to Enum.RenderPriority.Input.Value + 1 (Right after input was registered) to be more precise.

  2. Use a generalized loop, and if OnTouch is not planned to contain any yielding logic, don’t even wrap it in a coroutine. If it is, however, use task.spawn instead, as coroutine.wrap obscures error messages making debugging hard.

2 Likes

how do i do that?_____________________

2 Likes

this is what i ment and what needed to be checked every frame

2 Likes

Like you would with other connections, except you are passing the callback to a method and not a signal.

local function OnRenderStep()
	for _, Region in RegionList  do
		OnTouch(Region)
	end
end

RunService:BindToRenderStep("CheckRegions", Enum.RenderPriority.Input.Value + 1, OnRenderStep)
2 Likes

my performance increased from 16 to 32fps the song plays great at ~40-50 fps but for like chorus, it drops again and the script runs ~32 memory again. maybe i still have too many notes in one chunk

2 Likes

What is this code trying to accomplish? I feel like there needs to be some more context so we aren’t just running at an XY problem.

1 Like

its a ui intersection script. its trying to loop through every imagebutton and check if its overlapping a main gui

ie:

playhead and MIDI notes

1 Like

It might be worth profiling your code to see what is actually causing the lag.

1 Like

i have another script that is accociated with this one but i cant pull it up because roblox is down

1 Like

If it is just looping through all the UI elements which is causing the lag, you could implement some kind of partitioning system where UI elements are grouped together based on their location. You would only need to loop through the partition where the line actually is, reducing the amount of time it takes.

Also, I’m not super certain on the internal workings of UIStroke, but it might take less memory to just have a few instances of UIStroke. As the line moves, you reparent them to the individual notes.

1 Like

i have, ive created a render system but i think even that is flawed, ima bring up an auto save to find it if i can. but it renders up to 700+ notes in one screen out of the 10k notes in total

for i, frame in pairs(game.CollectionService:GetTagged("Chunk")) do
	local playerhead = frame.Parent.Parent.DragableFrame

	local collectionservice = game:GetService("CollectionService")
	if frame:IsDescendantOf(script.Parent) then
		local id = tostring(frame.Parent.Parent.Parent.Parent.ID.Value..frame.Name) 
		local guiInset = game:GetService("GuiService"):GetGuiInset()


		local function isInScreen()
			local pos = frame.AbsolutePosition + guiInset
			return pos.X + frame.AbsoluteSize.X <= frame.Parent.Parent.AbsolutePosition.X+frame.Parent.Parent.AbsoluteSize.X and pos.X >= -frame.Parent.Parent.AbsoluteSize.X
		end



		frame.Parent.Parent.Octaves.DescendantAdded:Connect(function(child)
			task.wait()
			if not game.CollectionService:HasTag(child,"notes") then return end
			if child.AbsolutePosition.X >= frame.AbsolutePosition.X and child.AbsolutePosition.X <= frame.AbsolutePosition.X+frame.AbsoluteSize.X then

				collectionservice:AddTag(child,id)
				child.assets.Chunk.Value = frame
				if isInScreen()  then
					collectionservice:AddTag(child,"regions")
					child.Visible = true
				else
					collectionservice:RemoveTag(child,"regions")
					child.Visible = false
					child.MakeGUIDraggable.Enabled = false
					child.MakeGUICopyable.Enabled = false
				end	
			end
		end)

		frame.Parent.Parent.Octaves.DescendantRemoving:Connect(function(child)
			if not game.CollectionService:HasTag(child,"notes") then return end
			if child.AbsolutePosition.X >= frame.AbsolutePosition.X and child.AbsolutePosition.X <= frame.AbsolutePosition.X+frame.AbsoluteSize.X then
				collectionservice:RemoveTag(child,id)
			end
		end)

		frame.Parent.Parent:GetPropertyChangedSignal("CanvasPosition"):Connect(function()
			wait()
			if isInScreen()  then
				if frame.rendered.Value == true then return end
				frame.rendered.Value = true
				frame.BackgroundColor3 = Color3.new(1, 1, 1)
				for i, v in pairs(collectionservice:GetTagged(id)) do
					collectionservice:AddTag(v,"regions")
					v.Visible = true
				end
			else
				if frame.rendered.Value == false then return end
				frame.rendered.Value = false
				frame.BackgroundColor3 = Color3.new(0.333333, 0.333333, 0.498039)
				for i, v in pairs(collectionservice:GetTagged(id)) do
					collectionservice:RemoveTag(v,"regions")
					v.Visible = false
					v.MakeGUIDraggable.Enabled = false
					v.MakeGUICopyable.Enabled = false
				end
			end
		end)
	end
end

and there are multiple of these running per piano roll. and each piano roll has about ~256 renderframes each the size of the screen

1 Like

wait no it wasnt my render system, it was accually my tween sounds, every sounds played tweens its volume to 0 befor destroyed. i did this for a fading effect but too many tweens lag my pc

1 Like

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