How to reduce a intvalue?

Hey, is there any alternative way to this code


	for _, v in pairs(Boosts:GetChildren()) do
		if v:IsA("ValueBase") then
			coroutine.resume(coroutine.create(function()
				while true do
					task.wait(5)
					if Player then
						if v.Value > 0 then
							v.Value -= 1

						else
							v.Value = 0
						--	break
						end
					else
						break
					end
				end
			end))
		end
	end

So the valuebases are basically boosts like ‘X2EXP’, that reduce every 5 seconds by 1, is there a way I can do this without a while loop?

Why do you want to do it without a while loop? You can use a for loop, but it ultimately doesn’t matter.

Because while loops could be extensive on the server

They won’t be. A while loop is just like a for loop. It’s just one “step” in the code, and it chains together the “steps” contained within. If you don’t have any pauses, then you basically get a really long sequence of steps. With an infinite loop, that’s an infinitely long sequence of steps. But this isn’t infinite, and it’s not even very long. You see, you’re waiting five seconds in between executions. So every loop, the sequence of steps takes a break for other scripts on the thread to run for 5 seconds, an eternity in computer time. Then this code runs 10 more steps taking about a microsecond, then another eternity of computer time for other tasks to run. This is about as non-intensive as you can get.

If you insist on not using a while loop, you can use .Changed() event to detect when the int value is changed, and decrease by 1 after 5 seconds.

IntValue.Changed:Connect(function()
     if IntValue.Value > 0 then
          wait(5)
          IntValue.Value -= 1
     end
end)

Uh there is an alternative way to achieve the same functionality without using a while loop. Instead, you can use a combination of a Timer and a Heartbeat connection to periodically decrease the Value of the ValueBases.

local function decreaseValue()
for _, v in pairs(Boosts:GetChildren()) do
if v:IsA(“ValueBase”) then
if v.Value > 0 then
v.Value -= 1
else
v.Value = 0
end
end
end
end

local function startDecreasingValues()
local timer = 0
local interval = 5 – Decrease every 5 seconds

local heartbeatConnection
heartbeatConnection = game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
    timer += deltaTime
    if timer >= interval then
        timer -= interval
        decreaseValue()
    end
end)

end

startDecreasingValues()

1 Like

Assuming it’s something like the player has 2x EXP for x amount of time it depends on how complicated you wanna get with it. The best way I can think of efficiency wise if you have nothing displaying the remaining time you can probably get away with just using a task.wait with no loop and if your saving it on the player leaving you could get the os.time at the beginning of the wait and than on playerleaving check the current os.time and subtract them to get the remaining time of the wait to save if the wait hasn’t ended. Though I recommend just looping it since it’s really not that intensive when you have a 5 second wait between each loop anyway.

I want to point out that this type of system in this scenario has similar or worse efficiency compared to a while loop. Not that it’s inefficient, and it’s a perfectly reasonable approach. I just want to point out that there’s nothing wrong with while loops.

You’ll also need to adapt the system to reset the timer whenever the value is changed.

This is actually worse. Instead of letting the high-performance C++ backend resume the code every 5 seconds, you’re running several lines of low-performance Lua code approximately 300 times before the timer even expires.

Again, I don’t want to knock your code. It’s not an unreasonable approach and it won’t harm performance much, if at all. But if we’re being ultra-concerned about efficiency here, a simple loop is probably the way to go.

1 Like