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

How to make this sprint take away stamina?

Asked by
soutpansa 120
6 years ago
Edited 6 years ago

I grabbed a free model "shift to run" script to play around with for a small little project. I'm trying to make it take stamina away from the player, but all it does is take the stamina and then nothing else. Any ideas on what I'm doing wrong?


local mouse = game.Players.LocalPlayer:GetMouse() local running = false function getTool() for _, kid in ipairs(script.Parent:GetChildren()) do if kid.className == "Tool" then return kid end end return nil end mouse.KeyDown:connect(function (key) key = string.lower(key) if string.byte(key) == 48 and game.Players.LocalPlayer.Levelss.Vampire.Value == 0 then running = true while true do wait() if running == true then game.Players.LocalPlayer.Levelss.Stamina.Value = game.Players.LocalPlayer.Levelss.Stamina.Value - 5 end end local keyConnection = mouse.KeyUp:connect(function (key) if string.byte(key) == 48 then running = false end end) for i = 1,5 do game.Workspace.CurrentCamera.FieldOfView = (70+(i*2)) wait() end game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = game.Players.LocalPlayer.Character.Humanoid.WalkSpeed + 7 repeat wait () until running == false keyConnection:disconnect() game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = game.Players.LocalPlayer.Character.Humanoid.WalkSpeed - 7 for i = 1,5 do game.Workspace.CurrentCamera.FieldOfView = (80-(i*2)) wait() end end end) mouse.KeyDown:connect(function (key) key = string.lower(key) if string.byte(key) == 48 and game.Players.LocalPlayer.Levelss.Vampire.Value == 1 then running = true while true do wait() if running == true then game.Players.LocalPlayer.Levelss.Stamina.Value = game.Players.LocalPlayer.Levelss.Stamina.Value - 5 end end local keyConnection = mouse.KeyUp:connect(function (key) if string.byte(key) == 48 then running = false end end) for i = 1,5 do game.Workspace.CurrentCamera.FieldOfView = (70+(i*2)) wait() end game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = game.Players.LocalPlayer.Character.Humanoid.WalkSpeed + 15 repeat wait () until running == false keyConnection:disconnect() game.Players.LocalPlayer.Character.Humanoid.WalkSpeed = game.Players.LocalPlayer.Character.Humanoid.WalkSpeed - 15 for i = 1,5 do game.Workspace.CurrentCamera.FieldOfView = (80-(i*2)) wait() end end end)

1 answer

Log in to vote
0
Answered by
Pyrondon 2089 Game Jam Winner Moderation Voter Community Moderator
6 years ago

Before getting to the actual problems, there are a couple of things fundamentally wrong with this. I'll list and address them in order, I suppose:

  • The first issue is that you have two functions connected to the event. While this isn't necessarily an issue, a much more organised way would be to have them under one.
  • There are multiple uses of game.Players.LocalPlayer; you should create variables for stuff you're using a lot.
  • You're using Mouse.KeyDown, which is deprecated. You should use UserInputService or ContextActionService instead.

The script is also just rather messy, in general. So, let's tackle them in order.
The first part should be simple to fix; it looks like the only differences are the check of Vampire.Value and the number which is added. So, knowing this, we should be able to merge the two functions rather easily.

I also pointed out that you should use a variable for game.Players.LocalPlayer, so let's add that in as well.


local player = game:GetService("Players").LocalPlayer;
local mouse = player:GetMouse()
local running = false

function getTool()  
    for _, kid in ipairs(script.Parent:GetChildren()) do
        if kid.className == "Tool" then return kid end
    end
    return nil
end

mouse.KeyDown:Connect(function(key)
    key = string.lower(key)
    if string.byte(key) ~= 48 then return end;
    local delta;
    if player.Levelss.Vampire.Value == 0 then --// You may be better off using a BoolValue here.
        delta = 7;
    else
        delta = 15;
    end;

    running = true
    while  true do
        wait()
        if running == true then
            player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5

        end

    end
    local keyConnection = mouse.KeyUp:connect(function (key)
        if string.byte(key) == 48 then
            running = false
        end
    end)
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (70+(i*2))
        wait()
    end
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed +  delta --// Using the delta value, which was set earlier.
    repeat wait () until running == false
    keyConnection:disconnect()
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed - delta 
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (80-(i*2))
        wait()
    end
end)

Okay, that wasn't too bad. Now that the script is a bit more straightforward, we can deal with the other issues. As I said before, Mouse.KeyDown is deprecated (Mouse.KeyUp, as well). Personally, I prefer UserInputService, although ContextActionService has its perks and is more useful in certain contexts. In this case, however, I'm going to use UserInputService.

UserInputService methods may look a bit different from Mouse.KeyDown, but they're really quite straightforward.


local player = game:GetService("Players").LocalPlayer;
local UIS = game:GetService("UserInputService");
local running = false

function getTool()  
    for _, kid in ipairs(script.Parent:GetChildren()) do
        if kid.ClassName == "Tool" then return kid end --// Not super related, but `className` is deprecated. Use `ClassName` instead.
    end
    return nil
end

UIS.InputBegan:Connect(function(input, gameProcessedEvent)
    if gameProcessedEvent then return end; --// If it was pressed on top of a GUI, return.
    local key = input.KeyCode;
    if key ~= Enum.KeyCode.RightShift then return end;
    local delta;
    if player.Levelss.Vampire.Value == 0 then --// You may be better off using a BoolValue here.
        delta = 7;
    else
        delta = 15;
    end;

    running = true
    while  true do
        wait()
        if running == true then
            player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5

        end

    end
    local keyConnection = UIS.InputEnded:Connect(function(input, gpe)
        if input.KeyCode == Enum.KeyCode.RightShift then
            running = false
        end
    end)
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (70+(i*2))
        wait()
    end
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed +  delta --// Using the delta value, which was set earlier.
    repeat wait () until running == false
    keyConnection:disconnect()
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed - delta 
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (80-(i*2))
        wait()
    end
end)

Alright, that conversion is out of the way. Now we can get to the real issues!


For this bit, I'll focus on a few smaller sections of the code. The first, and most prominent error would probably be the infinite loop you've got going on:

while  true do
    wait()
    if running == true then
        player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5

    end

end

You may be thinking, "But that isn't infinite, it only runs if running is true!"
The thing is, not only does the loop itself keep going even if running is no longer true, running will never not be true, because the event connection directly beneath the loop never runs. I'll get to that in a bit.

The two big flaws here are messed-up order of execution (as I just pointed out) and lack of a loop condition.

As for the loop condition, you could break the loop like this:

while  true do
    wait()
    if running == true then
        player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5
    else
        break
    end
end

And it works, sure. But why do that when you can just as easily, and a bit more cleanly, do this?

while running do
    wait()
    player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5
end

Alright, now we've set up the loop condition. The bigger issue here would be the order of execution. Right now, this section of code looks like this:

running = true
while running do
    wait()
    player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5
end
local keyConnection = UIS.InputEnded:Connect(function(input, gpe)
    if input.KeyCode == Enum.KeyCode.RightShift then
        running = false
    end
end)
for i = 1,5 do
    game.Workspace.CurrentCamera.FieldOfView = (70+(i*2))
    wait()
end
player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed +  delta -

--// More stuff...

The logic is all over the place. It might seem to make sense when looking at the script, but let's describe the first two things happening, in order.

  1. While running is true, decrease the stamina value.
  2. Connect an event to set running to false when shift is released.

This already doesn't seem right. How is it going to get to the second step if it's still looping in the first step!?

Short answer: it can't. And it can't reach any of the code in the function below that point, either.

But we already know it doesn't work, so how do we fix it? Easy, just change what the problem was: the order of execution. If you need the event to be connected before the loop starts, you should, well.. do it before the loop. Same with the WalkSpeed change, and the camera effects.


local player = game:GetService("Players").LocalPlayer;
local UIS = game:GetService("UserInputService");
local running = false

function getTool()  
    for _, kid in ipairs(script.Parent:GetChildren()) do
        if kid.ClassName == "Tool" then return kid end --// Not super related, but `className` is deprecated. Use `ClassName` instead.
    end
    return nil
end

UIS.InputBegan:Connect(function(input, gameProcessedEvent)
    if gameProcessedEvent then return end; --// If it was pressed on top of a GUI, return.
    local key = input.KeyCode;
    if key ~= Enum.KeyCode.RightShift then return end;
    local delta;
    if player.Levelss.Vampire.Value == 0 then --// You may be better off using a BoolValue here.
        delta = 7;
    else
        delta = 15;
    end;

    local keyConnection = UIS.InputEnded:Connect(function(input, gpe)
        if input.KeyCode == Enum.KeyCode.RightShift then
            running = false
        end
    end)
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (70+(i*2))
        wait()
    end
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed +  delta

    running = true
    while running do
        wait()
        player.Levelss.Stamina.Value = player.Levelss.Stamina.Value - 5
    end
    --// repeat wait () until running == false -> This line is useless, and can be removed.
    keyConnection:Disconnect() --// `disconnect` is deprecated, use `Disconnect` instead.
    player.Character.Humanoid.WalkSpeed = player.Character.Humanoid.WalkSpeed - delta 
    for i = 1,5 do
        game.Workspace.CurrentCamera.FieldOfView = (80-(i*2))
        wait()
    end
end)

Really, that's about it for the real script-breaking problems. You can improve upon the code in a few ways, such as:

  • Using IsA() rather then ClassName.
  • Using a BoolValue for Vampire, as I noted in the code.
  • Using running as a debounce (if running then return end) at the start of the function, so it can't be triggered while it's already happening.

But, for the most part, it should be good.
Hope this helped, and hope you learned some stuff.


Read more about InputObjects, KeyCodes, and ContextActionService.

Ad

Answer this question