Help with Stamina System (Memory Leak)

Hello, I am making a stamina system for my fighting game.
I have a few problems with it though,

  1. It causes lots of lag
  2. It causes a client-sided memory leak
  3. I need to optimize my code to be more efficient.

Basically how my system is set out is that there’s a ModuleScript that is accessible by _G from the client. The Module has a few functions which include:

Functions in the Module
local MaxStamina = 100
local Stamina = MaxStamina

local StaminaChanged = script:FindFirstChild("StaminaChanged") -- This is a BindableEvent, btw

function module:IncrementStamina(Integer)
	if Integer ~= nil then
		if typeof(Integer) == 'number' then
			Stamina = math.clamp(Stamina + Integer, 0, MaxStamina)
			
			StaminaChanged:Fire(Stamina)
		end
	end
end

function module:SetStamina(Integer)
	if Integer ~= nil then
		if typeof(Integer) == 'number' then
			Stamina = Integer

			StaminaChanged:Fire(Stamina)
		end
	end
end

function module:GetStamina()
	return {Stamina, MaxStamina}
end

And then there’s a LocalScript that controls the regeneration.

local PlayerModule = _G.PlayerModule
local StaminaChanged = PlayerModule:WaitForChild("StaminaChanged", 0.1)
PlayerModule = require(PlayerModule)
local MaxStamina = PlayerModule:GetStamina()[2]
local LastStamina = PlayerModule:GetStamina()[1]

local RegenStartTime = 2 -- Time to wait before starting the regeneration
local Incrementing = false

StaminaChanged.Event:Connect(function(NewStamina)
	if NewStamina < LastStamina then
		if Incrementing == true then
			Incrementing = false
		end
	end
	spawn(function()
		wait(RegenStartTime)
		if PlayerModule:GetStamina()[1] == NewStamina then
			Incrementing = true
			while Incrementing == true do
				if PlayerModule:GetStamina()[1] ~= MaxStamina then
					PlayerModule:IncrementStamina(0.1)
				else
					Incrementing = false
					break
				end
				wait()
			end
		end
	end)
	LastStamina = NewStamina
end)

The scripts that deduct stamina also work similarly to this as well, they utilize while loops that run while conditions are met and then they eventually stop when those conditions are different.
I need urgent help because I’m planning to optimize my game as much as possible.
Thank you.

1 Like
StaminaChanged.Event:Connect(function(NewStamina)
	if not Incrementing then
		return
	end

You should probably do this, otherwise the event could be fired multiple times resulting in the execution of multiple spawn tasks which are calling multiple functions every frame.

Why are you spawning…? You need to re-evaluate how to handle this.

I feel like this wouldn’t work because the ‘Incrementing’ boolean is false on default resulting in the function not working.

Why can’t I spawn(function()?

Remove spawn(function() since Events start new threads automatically so its not needed and you’re just stacking another thread where one isn’t needed.

Instead of a while loop you should try using RunService.RenderStepped/RunService.PostSimulation.

Also use task.wait() its better than normal wait() and when passed without arguments has a 2x lower wait time since it acts like RunService.Heartbeat:Wait(). (wait is .03 which is 2 frames and task.wait is .015 which is a single frame)

1 Like

That would need to be changed also, initially set it to true.

I wouldn’t recommend to use global variables as they’re not encouraged to be used in new works.

I recommend you to use the task library instead of using these legacy functions to yield and spawn threads.

I also wouldn’t try to spawn threads to handle the stamina regeneration because it’s going to eat a lot of memory, plus your threads would NEVER die or garbage collected because there is a continuos while loop in it.

.Event is a member of BindableEvent

Edit since I don’t want to make another post:

Directly from the Announcements post about the new task library

1 Like

No. RenderStepped shouldn’t be used if the code doesn’t involve the camera. Use RunService.Heartbeat instead.

Also, task.wait() isn’t the same as RunService.Heartbeat:Wait() as RunService Heartbeat returns the amount of seconds elapsed since the previous heartbeat(physics simulation) is done while task’s wait returns the number of seconds elapsed since the last call of this function.

Hello, unfortunately your suggestion to resolve my problem didn’t work.
It did not regenerate even though the function fired.

Thank you for the help, it works!

I didn’t really make an effort to check out the issue thoroughly when replying so I apologise for that.

It’s fine, thank you for the help though!