Does separating code into scripts reducing lag?

The title. Or does it not, because the threading isn’t REALLY parallel. I’m asking this because my game so far is good, and is so close to being able to be published, but it’s just so laggy. It’s impossible to play on any low end devices because of it. So I tried splitting it up into separate scripts, but I’m wondering if it actually even does anything? If you need more information, just request it.

2 Likes

Most likely not. It’s not as simple as “the engine can’t read all those lines of code fast enough.” Believe it or not, Roblox has a decent capability of scanning through scripts and finding relevant pieces of code to run. If I have a script that has 20k lines of code, it will probably run just as fast as a script with just 10 lines of code.

The problem arises within your code. There are a million reasons why your game could be laggy. Perhaps you have inefficient loops. Perhaps you’re calling the same functions over and over. Perhaps you’re making lots of calls to the server, slowing it down. To really find out why your game is laggy, you’ll need to do a close read of your code. Make sure you’re using best practices. Make sure you’re using debounces and whatnot to slow down requests to the server.

Honestly, you’ll just have to look through your code and try to figure out what exactly you’ve done that’s slowing the scripts down.

2 Likes

If you’re talking about splitting into multiple ModuleScripts, it most likely won’t do much other than improve code readability (no need to scroll past long scripts).

What matters is how optimized your code is. If you have multiple scripts doing the exact same task in different locations (many scripts updating the Transparency of its parent Part), that can cause lag. Abusing (or wrongly using) coroutines or task.spawn() can also cause lag, especially when the coroutine/thread is a while true do loop. You might be also using expensive calculations in a loop.

The causes of lag depend on how unoptimized your code is.

1 Like

I think you answered your own question and I agree the logic is sound there.

However, it might be a good idea as you are able to monitor the script activity from it and judge which script is the culprit as the other replies said.

Also consider other measurements of performance mainly the microprofiler.

2 Likes

This. Probably the best way to check what’s slowing down your code is to start putting print statements in your loops or other pieces of code. See how many print statements are populated to the server. If there’s a ton of prints, that piece of code could be slowing down the server.

2 Likes

Heh, I think I’m guilty of this.

task.spawn(function()
			while task.wait(createmodule.sizespeedsumxprefreshrate) do
				if circle.Parent == nil then break end
				
				local sum = 0
				for _, v in circle.Units:GetChildren() do -- increment speed and sumxp
					v:SetAttribute("Speed", createmodule.speed(v:GetAttribute("XP")))
					v.Size = v.Size:Lerp(createmodule.resize(v), createmodule.resizespeed)
					sum += v:GetAttribute("XP")
				end
				
				circle:SetAttribute("SumXP", sum)
				plr.leaderstats.Size.Value = sum
			end
		end)
		task.spawn(function() -- handle size
			while task.wait(createmodule.masslossrefreshrate) do
				if circle.Parent == nil then break end
				
				for _, v in circle.Units:GetChildren() do
					v:SetAttribute("XP", createmodule.xpLoss(v:GetAttribute("XP")))
				end
			end
		end)
		task.spawn(function() -- splittimes and merge
			while task.wait(createmodule.scoresplitrefreshrate) do
				if circle.Parent == nil then break end
				
				for _, v in circle.Units:GetChildren() do
					v:SetAttribute("SplitTime", math.max(v:GetAttribute("SplitTime") - createmodule.scoresplitrefreshrate, 0))
					v:SetAttribute("CanMerge", v:GetAttribute("SplitTime") == 0)
				end
				circle:SetAttribute("Score", circle:GetAttribute("Score") + (createmodule.scorespeed * createmodule.scoresplitrefreshrate))
			end
		end)
		task.spawn(function() -- eat xp and other players
			while task.wait(createmodule.eatrefreshrate) do
				if circle.Parent == nil then break end
				local cur_circles = circles:GetChildren()
				local cur_units = circle.Units:GetChildren()

				for _, v in xps:GetChildren() do
					for _, w in cur_units do
						if createmodule.isEating(w, v) then
							w:SetAttribute("XP", w:GetAttribute("XP") + v:GetAttribute("XP"))
							circle:SetAttribute("Score", circle:GetAttribute("Score") + 10)
							v:Destroy()
						end
					end
				end
				for _, v in viruses:GetChildren() do
					for _, w in cur_units do
						if createmodule.isEating(w, v) then
							if v:GetAttribute("XP") * 1.25 <= w:GetAttribute("XP") then
								w:SetAttribute("XP", w:GetAttribute("XP") + v:GetAttribute("XP"))
								local angle = math.random(2 * math.pi)
								createmodule.split(circle, w, Vector3.new(math.cos(angle), 0, math.sin(angle)), true)
								
								circle:SetAttribute("Score", circle:GetAttribute("Score") + 10)
								v:Destroy()
							end
						end
					end
				end
				for _, v in cur_circles do
					if v then
						if v ~= circle then
							for _, w in v.Units:GetChildren() do
								for _, x in cur_units do
									if v:GetAttribute("IsAlive") then
										if createmodule.isEdible(x:GetAttribute("XP"), w:GetAttribute("XP")) then
											if createmodule.isEating(x, w) then
												x:SetAttribute("XP", x:GetAttribute("XP") + w:GetAttribute("XP"))
												circle:SetAttribute("Score", circle:GetAttribute("Score") + 55)
												w:Destroy()
											end
										end
									end
								end
							end
						end
					end
				end
			end
		end)
2 Likes

in the console it says the script that runs this is 58% active. But please, any nitpicks you have in this code, please, pretty please point them out, because it WILL help.

1 Like

These can mostly be replaced with functions connected to events. These functions run all the time even if they don’t need to.

2 Likes

Is SetAttribute() and GetAttribute() relatively taxxing? I’m guessing it is, because it’s working with instances.

1 Like

They shouldn’t cause any lag and are preferred to using ValueObjects.

One more tip: You can split parts of these functions into “helper functions” (any part of the code that is noticeably repeated can be separated into its own function, which can then be called by other code).

One example:

Can be its own function (This is based on how I understood your code, so I may be wrong here):

local function consume(exp : Instance, add_exp : Instance, extra_exp : number?)
	exp:SetAttribute("XP", exp:GetAttribute("XP") + add_exp:GetAttribute("XP"))
	circle:SetAttribute("Score", circle:GetAttribute("Score") + (extra_exp or 0))
	add_exp:Destroy()
end
1 Like

I heard that function calls can be expensive. Is this true? If so would it be noticeably faster? Or should I not waste my time?

1 Like

Depends on the language and usage, although function calls do have performance impacts (when used in a massive loop, like a thousand iterations or more). This is probably negligible, though, if you avoid too many while loops calling it.

2 Likes

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