Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Loops can't properly stop, why?

So, i have this function connected via Left Shift. It activates every time you press that key. If you rapidly press or release Left Shift, not sprinting will regenerate more stamina and sprinting will wear off stamina faster, accordingly, until you stop pressing or releasing the button rapidly.

I haven't been able to solve this predicament to date, although i do have a clue: The sprinting value appears to be true or false when the loop is to check the conditions, depending on what you do rapidly. Even adding debounce didn't help.

Here's the script, with added comments:

local function Sprint(_,state)
	if state == Enum.UserInputState.Begin then --Sprint
		if script.Parent.Stamina.Value < 15 then return end --Minimum stamina needed
		game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 29
		script.Parent.Sprinting.Value = true --Sprinting
		script.Parent.Stamina.Value = script.Parent.Stamina.Value - 3
		while script.Parent.Stamina.Value > 0 and script.Parent.Sprinting.Value do --Drain stamina
			script.Parent.Stamina.Value = script.Parent.Stamina.Value - 1
			wait(0.15)
		end
	else --Stop sprinting (releasing left shift)
		game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = 12
		script.Parent.Sprinting.Value = false --Not sprinting
		wait(1)
		while script.Parent.Stamina.Value <= 100 and not script.Parent.Sprinting.Value do --Regen stamina
			wait(0.5)
			script.Parent.Stamina.Value = script.Parent.Stamina.Value + 1
		end
	end
end

game.ContextActionService:BindAction("Sprint", Sprint, false, Enum.KeyCode.LeftShift)

1 answer

✓ Accepted answer

It can be dangerous and confusing to start loops inside events. It usually much simpler for events to simply direct the behavior of loops. The problem with your current design is that the same action (or different action) are allowed to be happening at the same time. It's sort of tedious to stop this from happening.

There's a cleaner way to write this sort of behavior.

I'll be writing using variables instead of _Value objects, because it's briefer. If you have multiple scripts looking at these values, though, you'd have to switch it back.

This is a much simpler way to write what you want -- there's only ever one thing happening at a time (instead of many, one for each keypress):

local sprinting = false -- Initially, you don't start running
local stamina = 100 -- Initially, you start with full stamina

local function Sprint(_, state)
	-- Begin or end sprinting:
	sprinting = state == Enum.UserInputState.Begin
end

game.ContextActionService:BindAction("Sprint", Sprint, false, Enum.KeyCode.LeftShift)

while true do
	local dt = wait(0.15) -- Record ACTUAL time that has elapsed
	-- (instead of hoping it's actually .15, which it may not be)
	local humanoid = game.Players.LocalPlayer.Character.Humanoid
	if sprinting and stamina > 1 then
		humanoid.WalkSpeed = 29 -- (run)
		stamina = math.max(0, stamina - dt * 20/30) -- drain, down to 0
	else
		sprinting = false -- (stop sprinting if you're out of energy))
		humanoid.WalkSpeed = 12 -- (walk)
		stamina = math.min(stamina + dt * 2, 100) -- regenerate, up to 100
	end
end

1 comment

0

The main idea solved it nicely. Thank you BlueTaslem, and good luck for 3k!

This discussion is preserved as it was. New answers, comments, and votes are closed.