While wait(0.1) do loop mysteriously increases interval

I’m working on a game, and I’ve encountered with this big problem. I have a script that handles a lot of stuff like collecting gear, selling gear for parts, spending parts on other tiles This script uses a while loop that runs every 0.1 seconds. Things are going okay, except the fact that, only in the real game, the 0.1 second interval goes to 0.11, 0.12, 0.13, 0.14, etc. very slowly. I checked this by recording how long it takes for the task of the while loop to execute and rerun. Normally it should fluctuate, but instead it’s slowly going up and up. If you’re wondering, here’s the code:

local signals = game.ReplicatedStorage.Signals
local modules = game.ReplicatedStorage.Modules

-- Modules
local ids = require(modules.Ids)

local character = script.Parent
local player = game.Players:GetPlayerFromCharacter(character)
local playerStorage = game.ServerStorage.PlayerData:WaitForChild(player.Name)
local inZone = false
local sellArea = Vector3.new(0.688, 3.583, 5.179)

character.Humanoid.CameraOffset = Vector3.new(0, 1, 0)
character:MoveTo(player:WaitForChild("Plot").Value.SpawnLocation.Position)

while wait(0.1) do
	local gear
	
	if not character.PrimaryPart then -- Character died
		break
	end
	
	local ignoreList = {game.Workspace.RobotGround}
	
	for i, v in pairs(game.Players:GetPlayers()) do
		table.insert(ignoreList, v.Character)
	end
	
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = ignoreList
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	
	local hit = game.Workspace:Raycast(character.PrimaryPart.Position, Vector3.new(0, -10, 0), raycastParams)
	local pickupGears = nil
	
	spawn(function()
		if hit then
			if hit.Instance:FindFirstAncestor("World") and player.Plot.Value == hit.Instance:FindFirstAncestor("World").Parent then -- Making sure it's the player's plot
				if hit.Instance.Parent:FindFirstChild("PriceGui") and hit.Instance.Parent.Name ~= "EggCapsule" then -- Make sure it's a tile
					signals.ClaimTile:Fire(player, hit.Instance.Parent)
				elseif hit.Instance.Parent:FindFirstChild("EggCapsule") then
					if (character.PrimaryPart.Position - hit.Instance.Parent.EggCapsule.Base.Position).Magnitude <= 5 then
						local result = signals.ClaimEgg:Invoke(player, hit.Instance.Parent)
						
						if result then
							signals.OpenEggCapsule:FireClient(player)
						end
					end
				elseif hit.Instance.Parent.Name == "EggCapsule" then
					if (character.PrimaryPart.Position - hit.Instance.Parent.Base.Position).Magnitude <= 5 then
						local result = signals.ClaimEgg:Invoke(player, hit.Instance.Parent.Parent)
						
						if result then
							signals.OpenEggCapsule:FireClient(player)
						end
					end
				elseif hit.Instance.Parent.Name == "Gears" then -- Gear tile
					gear = hit.Instance.Parent
				elseif hit.Instance.Parent:FindFirstChild("Gears") then
					if (character.PrimaryPart.Position - hit.Instance.Parent.Gears.PrimaryPart.Position).Magnitude <= 5 then
						gear = hit.Instance.Parent.Gears
					end
				end
			end
		end
		
		if (character.PrimaryPart.Position - sellArea).Magnitude <= 12 then
			if not inZone then
				inZone = true
				local gears = playerStorage.Gears
				local parts = playerStorage.Parts
				
				if gears.Value > 0 then
					parts.Value += gears.Value * 2
					playerStorage.TotalParts.Value += gears.Value * 2
					gears.Value = 0
				end
			end
		else
			inZone = false
		end
		
		if gear then
			local gears = playerStorage.Gears
			local parts = playerStorage.Parts
			
			if not gear:GetAttribute("Collected") then -- Collectable
				local multiply = 1
				
				if game.MarketplaceService:UserOwnsGamePassAsync(player.UserId, ids.Gamepasses["2xGear"]) then
					multiply = 2
				end
				
				if game.MarketplaceService:UserOwnsGamePassAsync(player.UserId, ids.Gamepasses.AutoSell) then
					parts.Value += math.ceil(player.leaderstats.World.Value * 3 * player.Multiplier.Value * multiply)
					playerStorage.TotalParts.Value += math.ceil(player.leaderstats.World.Value * 3 * player.Multiplier.Value * multiply)
				else
					gears.Value += math.ceil(player.leaderstats.World.Value * 3 * player.Multiplier.Value * multiply)
				end
				
				gear:SetAttribute("Collected", true)
				
				for i, v in pairs(gear:GetDescendants()) do
					if v:IsA("BasePart") then
						v.Transparency = 1
					end
				end
				
				delay(30, function()
					gear:SetAttribute("Collected", false)
					
					for i, v in pairs(gear:GetDescendants()) do
						if v:IsA("BasePart") then
							v.Transparency = 0
						end
					end
				end)
			end
		end
	end)
end

There are no errors in the output. I know the invoke function waits for data to be returned and can yield the script, but this still happens when we don’t use the invokes. Is there a reason why this is happening?

I cant remember the reason but i know that sometimes it goes off track you can get how much the wait actually waited by using local variableName = wait(0.1), perhaps you could use this somehow or you can use

while true do
wait(0.1)

Hope it helps

From what ive come across in the past, it seems the script is just too large to execute fully in a fraction of a second, perhaps break up the functions into smaller scripts?

Well wait() is deprecated (I know right) try use task.wait(0.1) instead

1 Like

Well it probably doesnt work in the actual game because of the server its running on, you cant perfectly loop that much code that fast

1 Like

The code works fine but i think the solutions might be working. It’s maintaining between 0.1 and 0.11 which is good