Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Loops can't properly stop, why?

Asked by
Marios2 360 Moderation Voter
9 years ago

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

Log in to vote
1
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago

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
0
The main idea solved it nicely. Thank you BlueTaslem, and good luck for 3k! Marios2 360 — 9y
Ad

Answer this question