Loop Stacking Bug

  1. Keep the sprinting system responsive and quick while also preventing the loops from stacking

Spamming the sprint button will cause more than 1 stamina to be taken away and way quicker than it should be, a sign that my loops are running multiple at a time
2. FunctionStacking

  1. De-bounce (Made the responsiveness too slow and just didn’t work, might not have used it right not sure)
--// Services

local rs = game:GetService("ReplicatedStorage")
local uis = game:GetService("UserInputService")
local tweenservice = game:GetService("TweenService")

--// Stamina Module
local staminamodule = rs.Framework:WaitForChild("StaminaHandler")
local staminahandler = require(staminamodule)

--// Player Attributes

local plr = game:GetService("Players").LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")

local cam = workspace.CurrentCamera

--// Attributes [Stamina]

local Stamina = char:SetAttribute("Stamina", math.clamp(100, 0, 100))

--// Debounce i think dunno

local IsSprinting = char:SetAttribute("IsSprinting", false)

--// Tweening

local info = TweenInfo.new(0.2, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false)
local tweenout = tweenservice:Create(cam, info, {FieldOfView = 80})
local tweenin = tweenservice:Create(cam, info, {FieldOfView = 70})

--// Function

local function SprintEnd(input, _gameProcessed)
	if input.KeyCode == Enum.KeyCode.LeftShift then
		if (char:GetAttribute("IsSprinting") == true) then
			char:SetAttribute("IsSprinting", false)

			humanoid.WalkSpeed = 12
			tweenin:Play()

			while (char:GetAttribute("IsSprinting") == false) do
				if (char:GetAttribute("IsSprinting") == false) then
					if not (char:GetAttribute("Stamina") >= 100) then
						task.wait(0.35)
						staminahandler:Add(1)
					else
						print("Won't add, at full stamina")
						return
					end
				end
			end
		end
	end
end

local function SprintRequest(input, _gameProcessed)
	if humanoid.MoveDirection.Magnitude > 0 then
		if input.KeyCode == Enum.KeyCode.LeftShift then
			char:SetAttribute("IsSprinting", true)

			humanoid.WalkSpeed = 18
			tweenout:Play()

			while (char:GetAttribute("IsSprinting") == true) do
				if (char:GetAttribute("IsSprinting") == true) then
					if not (char:GetAttribute("Stamina") <= 0) then
						task.wait(0.1)
						staminahandler:Remove(1)
					else
						SprintEnd(input, _gameProcessed)
						print("Exhausted!")
						return
					end
				end
			end
		end
	end
end

uis.InputBegan:Connect(SprintRequest)
uis.InputEnded:Connect(SprintEnd)
1 Like

I honestly don’t know why they stack (so it’s a bit of a shot in the dark), however maybe combining the sprint function will remove the stacking from occouring.
I have my sprint script like this:

function startSprint()
	sprinting = true 
end

function stopSprint()
	sprinting = false
end

function checkKey(key, isTyping, doSprint)
	if not isTyping then
		if key.KeyCode == sprintKey then
			if doSprint then
				startSprint()
			else
				stopSprint()
			end
		end
	end
end

uis.InputBegan:Connect(function(key, isTyping)
	checkKey(key, isTyping, true)
end)

uis.InputEnded:Connect(function(key, isTyping)
	checkKey(key, isTyping, false)
end)


game:GetService("RunService").Stepped:Connect(function()
	if sprinting then
		if stamina > 0 then
			if 1 == 1 then
				if uis:IsKeyDown(Enum.KeyCode.W) or uis:IsKeyDown(Enum.KeyCode.S) or uis:IsKeyDown(Enum.KeyCode.A) or uis:IsKeyDown(Enum.KeyCode.D) then
					if char.HumanoidRootPart.AssemblyLinearVelocity.Magnitude > 0.5 then
						if game.Workspace.CurrentCamera.CameraType == Enum.CameraType.Custom then
							stamina -= 0.02
							humanoid.WalkSpeed = sprintSpeed
							stamDecrease:FireServer(stamina)
						end
					end
				end
			end
		else
			humanoid.WalkSpeed = regularSpeed
		end
	else
		if stamina < maxStamina then
			stamina += maxStamina/500
			stamIncrease:FireServer(stamina)
		end
		if game.Workspace.CurrentCamera.CameraType == Enum.CameraType.Custom then
			humanoid.WalkSpeed = regularSpeed
		end
	end
	if stamina < maxStamina then
		plr.PlayerGui.Interface.bg.Bar:TweenSize(UDim2.new(stamina / maxStamina, 0, -1, 0), Enum.EasingDirection.In, Enum.EasingStyle.Linear, 0)
	end
end)

Problem with this is that because the function that removes or adds stamina is connected to run service, it will always be checking the stamina every step, which afaik has a toll on performance

1 Like

hmm that is possible. I don’t know much about peformance, so can’t say that the script is optimized peformance wise.

1 Like

Hi there,

I took a slightly different approach to this, separated the stamina handling into a singular while loop and an excruciatingly basic function for the sprint toggle purely out of logic and untested. I’m completely unsure if this is what you’re trying to achieve and if it will be compatible with the rest of your dependencies, but give it a shot:

--// Services

local rs = game:GetService("ReplicatedStorage")
local uis = game:GetService("UserInputService")
local tweenservice = game:GetService("TweenService")

--// Stamina Module
local staminamodule = rs.Framework:WaitForChild("StaminaHandler")
local staminahandler = require(staminamodule)

--// Player Attributes

local plr = game:GetService("Players").LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")

local cam = workspace.CurrentCamera

--// Attributes [Stamina]

local Stamina = char:SetAttribute("Stamina", math.clamp(100, 0, 100))

--// Debounce i think dunno

local IsSprinting = char:SetAttribute("IsSprinting", false)
local KeyDown = false -- Control variable to store the current status of the sprint key

--// Tweening

local info = TweenInfo.new(0.2, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut, 0, false)
local tweenout = tweenservice:Create(cam, info, {FieldOfView = 80})
local tweenin = tweenservice:Create(cam, info, {FieldOfView = 70})

--// Function

local function Sprint(status)
	if status then
		char:SetAttribute("IsSprinting", status)

		humanoid.WalkSpeed = 18
		tweenout:Play()
	else
		if (char:GetAttribute("IsSprinting") == true) then
			char:SetAttribute("IsSprinting", status)

			humanoid.WalkSpeed = 12
			tweenin:Play()
		end
	end
end

uis.InputBegan:Connect(function(input, _gameProcessed)
	if humanoid.MoveDirection.Magnitude > 0 then
		if input.KeyCode == Enum.KeyCode.LeftShift then
			KeyDown = true
			Sprint(true)
		end
	end
end)

uis.InputEnded:Connect(function(input, _gameProcessed)
	if input.KeyCode == Enum.KeyCode.LeftShift then
		KeyDown = false
		Sprint(false)
	end
end)

while task.wait() do
	if (char:GetAttribute("IsSprinting") == true) then
		if not (char:GetAttribute("Stamina") <= 0) then
			task.wait(0.1)
			staminahandler:Remove(1)
		else
			Sprint(false)
			print("Exhausted!")
		end
	elseif (char:GetAttribute("IsSprinting") == false) then
		if not (char:GetAttribute("Stamina") >= 100) then
			task.wait(0.35)
			staminahandler:Add(1)
			
			if KeyDown and (char:GetAttribute("Stamina") >= 20) then -- Continue the sprint once stamina has recharged upto 20
				Sprint(true)
				print("Running again!")
			end
		end
	end
end
3 Likes