Help with a running script!

Hey, i’m scripting a localscript fully dedicated to managing running in my game. What i do for now is connecting a function to UserInputService.InputBegan and UserInputService.InputEnded. What it does is toggling the run on and off.

Each character the player can use has a custom walking and running speed set in a module. What the toggle running function does is just changing the walkspeed of the player to either of those values.

Now i’ve ran into a problem. Throughout my match i want to be able to say, freeze the player. Or change the player’s walkspeed through a status effects (active like a Haste effect, or passive like being hit)

So if i freeze the player through the server, and the player just, runs, it will restart. Or if they are running and then frozen, or slowed down after stopping to run the walkspeed is reset to the normal walking speed and the freeze doesnt take effect.

How can i solve this? I already store plenty of value instances within the player. Should i make yet another one storing if the player’s running? I was thinking of using a heartbeat function instead too so i can add or remove multipliers from the player, is that a good idea or would that eat up cpu power?

If you’ve made something like this before and have an idea of how to do that i’d be thankful!

1 Like

I’m sorry but I don’t quite get what you are trying to achieve here. Can you please be a bit more specific? Do you have a suitable example to illustrate your goal here?

Put shortly, im switching the walkspeed of the player between two values with a function connected to the inputBegan and inputEnded events. However when i just, set the walkspeed to some other value like 0, if i want to freeze the player: running or stopping to will reset the speed back.

What would be the best way to set up a running script, with the ability without overcomplicating things?

I apologize if i wasnt really clear with my question

If you want to freeze the player, try anchoring the player’s HumanoidRootPart.

Add an attribute to either the Player or Character to tell the running script that they’re frozen and to not modify walkspeed.

if Instance:GetAttribute("isFrozen") then return end --// Replace "Instance" to either the Player or Character
Humanoid.WalkSpeed = ...

I mean a local script, instead of a module script would complicate this. But you could have it so anything wanting to change the speed of the player grabs a ticket and returns it when they no longer want to adjust the users speed. Then you can have ticket priorities and basically just always apply the highest priority ticket that is still in the system and no tickets means default walking speed. That way you can send like a freeze ticket with a priority 99 or something to force it to override every other possible effect.

So think like this

local DEFUALT_SPEED = 16
local humanoid = game.Players.LocalPlayer.Character:WaitForChild("Humanoid") --Not strictly safe, but good enough for the example
local tickets = {}

local function updateSpeed()
    local highestPriority = 0 --We assume all priorities are above 0 here btw
    local highestName = ""
    for name, info in pairs(tickets) do
        if info[1] > highestPriority then
            highestPriority = info[1]
            highestName = name
        elseif info[1] == highestPriority then
            if tickets[name][3] > tickets[highestName][3] then --Same priority, later submission overrides.
                highestName = name
            end
        end
    end
        
    if highestPriority == 0 then
        humanoid.WalkSpeed = DEFAULT_SPEED
    else
        humanoid.WalkSpeed = tickets[highestName][2] --[2] is the speed.  I could make them named or something for ease, but whatever.
    end
end


local SpeedModule = {}
function SpeedModule.SetSpeed(name, priority, speed)
    if tickets[name] then warn("Already have a ticket under the name: ", name) end
    if priority < 1 then error("Priority has to be 1 or higher for the speed system") end

    tickets[name] = {priority, speed, tick()}
    updateSpeed()
end

function SpeedModule.UnsetSpeed(name)
    if not tickets[name] then return warn("No ticket of name: ", name) end
    tickets[name] = nil
    updateSpeed()
end

return SpeedModule

It could potentially be cleaner if I just return a generated table when you make a ticket as a reference so that you can directly refer to it and just don’t have naming collisions at all. Probably better because it also helps enforce encapsulation since you can’t unbind a ticket from an unrelated script. But this does work. I would probably keep the names though for debugging. This strategy though could potentially go bad if you lose a reference to the table that you got when you made a ticket since you need it to return the ticket to prevent memory leaks and dead tickets being consumed, but that would be a usercode error, not an error here. The pure name version can potentially recover though since triggering the exit condition will always point to the correct name.