Toggleable Run Script

This should be relatively simple for other people but I just can’t figure out how to my this run script toggleable with the shift key. Currently its just if you hold it you sprint and when you let go you stop. I want it to be you sprint by clicking the key and stop by clicking it again. If you could help it would mean a lot.

local userInputService = game:GetService("UserInputService")
local players = game:GetService("Players")

local player = players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local hum = char:WaitForChild("Humanoid")
local animator = hum:WaitForChild("Animator")

local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://15720702879"
local track = animator:LoadAnimation(animation)
track.Priority = Enum.AnimationPriority.Movement

local running = false

local RUN_KEYCODE = Enum.KeyCode.LeftShift
local RUN_SPEED = 35
local WALK_SPEED = 16

local function run(runBool) -- So we don't have to repeat the same commands
	if runBool then
		if hum.MoveDirection.Magnitude <= 0 then return end -- If not moving then stop function execution

		hum.WalkSpeed = RUN_SPEED
		track:Play()
	else
		hum.WalkSpeed = WALK_SPEED
		track:Stop()
	end

	running = runBool
end

local function inputBegan(input, processed)
	if processed then return end

	if input.KeyCode == RUN_KEYCODE then
		run(true)
	end
end
local function inputEnded(input, processed)
	if processed then return end

	if input.KeyCode == RUN_KEYCODE then
		run(false)
	end
end

local function moveDirectionChanged()
	local magnitude = hum.MoveDirection.Magnitude
	if magnitude <= 0 then
		if running then
			run(false)
		end
	end
end

userInputService.InputBegan:Connect(inputBegan)
userInputService.InputEnded:Connect(inputEnded)

hum:GetPropertyChangedSignal("MoveDirection"):Connect(moveDirectionChanged)

Having a function that updates the character might get confusing, especially when dealing with sprinting (and having a check to check if your character isn’t moving, which a lot of games fail to do!). I would suggest using global variables to manage the states of your inputs, and using RunService to constantly check the inputs in order to play/stop animations and set the WalkSpeed as necessary!

I also want to note that the gameProcessed check in each of your inputBegan and inputEnded (more specifically for inputBegan) might return true if the player has shift lock enabled, so I disabled that check for now.

I assume this is placed in StarterCharacterScripts?

local userInputService = game:GetService("UserInputService")
local players = game:GetService("Players")
local RunService = game:GetService("RunService")

local player = players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local hum = char:WaitForChild("Humanoid")
local animator = hum:WaitForChild("Animator")

local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://15720702879"
local track = animator:LoadAnimation(animation)
track.Priority = Enum.AnimationPriority.Movement

local RUN_KEYCODE = Enum.KeyCode.LeftShift
local RUN_SPEED = 35
local WALK_SPEED = 16

local running = false
local key_down = false
local is_playing_animation = false

-- Plays running animation
local function playAnimation()
	if is_playing_animation then
		return
	end
	is_playing_animation = true
	track:Play()
end

-- Stops running animation
local function stopAnimation()
	if not is_playing_animation then
		return
	end
	is_playing_animation = false
	track:Stop()
end



local function run(runBool)
	if runBool then
		hum.WalkSpeed = RUN_SPEED
		playAnimation()
		print("RUNNING")
	else
		hum.WalkSpeed = WALK_SPEED
		stopAnimation()
		print("NOT RUNNING")
	end
end

-- Create a checker
local checker: RBXScriptConnection
checker = RunService.Heartbeat:Connect(function()
	-- If player gets respawned or dies, stop the checker
	if not char.Parent or hum.Health == 0 then
		checker:Disconnect()
		return
	end
	
	-- Update running states
	if running then
		if hum.MoveDirection.Magnitude > 0 then
			run(true)
		else
			run(false)
		end
	else
		run(false)
	end
end)



local function inputBegan(input, processed)
	--if processed then return end

	if input.KeyCode == RUN_KEYCODE then
		print("BEGAN")
		running = true
	end
end
local function inputEnded(input, processed)
	--if processed then return end

	if input.KeyCode == RUN_KEYCODE then
		print("ENDED")
		running = false
	end
end

local function moveDirectionChanged()
	local magnitude = hum.MoveDirection.Magnitude
	if magnitude <= 0 then
		running = false
	end
end

userInputService.InputBegan:Connect(inputBegan)
userInputService.InputEnded:Connect(inputEnded)

hum:GetPropertyChangedSignal("MoveDirection"):Connect(moveDirectionChanged)

I added print statement for debugging, feel free to remove them once you’re comfortable with how this works!

I changed your code a little to do this. Instead of passing a boolean as a function parameter into your run function, I instead store it in a global variable right above the function.
I also removed the InputEnded function, and instead added an if check inside the InputBegan.
Im not entirely sure what the moveDirectionChanged function is for, so I just left it untouched. Hence why there is your running variable, and my runBool variable. Hope this helps!

local userInputService = game:GetService("UserInputService")
local players = game:GetService("Players")

local player = players.LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()
local hum = char:WaitForChild("Humanoid")
local animator = hum:WaitForChild("Animator")

local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://15720702879"
local track = animator:LoadAnimation(animation)
track.Priority = Enum.AnimationPriority.Movement

local running = false

local RUN_KEYCODE = Enum.KeyCode.LeftShift
local RUN_SPEED = 100
local WALK_SPEED = 16

local runBool = false

local function run() -- So we don't have to repeat the same commands
	if runBool then
		if hum.MoveDirection.Magnitude <= 0 then return end -- If not moving then stop function execution

		hum.WalkSpeed = RUN_SPEED
		track:Play()
	else
		hum.WalkSpeed = WALK_SPEED
		track:Stop()
	end
end

local function inputBegan(input, processed)
	if processed then return end

	if input.KeyCode == RUN_KEYCODE then
		if runBool then runBool = false
		else runBool = true end
		
		run()
	end
end

local function moveDirectionChanged()
	local magnitude = hum.MoveDirection.Magnitude
	if magnitude <= 0 then
		if running then
			run(false)
		end
	end
end

userInputService.InputBegan:Connect(inputBegan)

hum:GetPropertyChangedSignal("MoveDirection"):Connect(moveDirectionChanged)
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.