I have a small problem, that is actually really hard for me to solve. My question is “How can I detect if player is still holding a button?” Let’s get into the details.
local SpeedValue_1 = 25
local SpeedValue_2 = 10
local SpeedValue_3 = 0
Character.Humanoid.Running:Connect(function(SpeedValue_4)
SpeedValue_3 = SpeedValue_4
print(SpeedValue_3)
end)
game:GetService('ContextActionService'):BindAction("ShiftSprint", function(actionName, inputState, inputObj)
if inputState == Enum.UserInputState.Begin and SpeedValue_3 > 1 then
Running = true
Character.Humanoid.WalkSpeed = SpeedValue_1
CamOut:Play()
CamIn:Pause()
RunAnimation:Play()
elseif inputState == Enum.UserInputState.Begin and SpeedValue_3 < 3 then
Running = false
Character.Humanoid.WalkSpeed = SpeedValue_2
CamIn:Play()
CamOut:Pause()
RunAnimation:Stop()
elseif inputState == Enum.UserInputState.End then
Running = false
Character.Humanoid.WalkSpeed = SpeedValue_2
CamIn:Play()
CamOut:Pause()
RunAnimation:Stop()
JumpAnimation:Stop()
ClimbAnimation:Stop()
SwimAnimation:Stop()
FallAnimation:Stop()
end
end, false, Enum.KeyCode.LeftShift)
Here is the problem:
When player starts walking and then starts holding LeftShift, he will start playing run animation, but if player stops walking or running(WASD) and holds LeftShift, run animation will still play, which I don’t want to happen. When player’s current speed is 0 or player is in idle form, but he is still holding a button for running, he won’t play run animation. So, I need some sort of help, to detect or track player’s speed in the function for Input. I don’t want to use loops for tracking, because loops grow lag in the game.
I tried placing the function that tracks player’s speed in the function for Input. Though, once I release the shift button and start walking, my player won’t walk, he will run (play run animation).
Is there any possible way how am I going to track player’s speed? If you think there is, please reply!
Thank you.
To answer the question about finding out if the player is still holding a button, use IsKeyDown of the UserInputService. To get a players speed you can do something like this:
local speed = (character.HumanoidRootPart.Velocity).magnitude;
local UserInputService = game:GetService("UserInputService")
UserInputService.InputBegan:Connect(function(inputObject, gameProcessed)
if gameProcessed then return end
if inputObject.KeyCode == Enum.KeyCode.LeftShift then
-- start sprinting
end
end
UserInputService.InputEnded:Connect(function(inputObject, gameProcessed)
if gameProcessed then return end
if inputObject.KeyCode == Enum.KeyCode.LeftShift then
-- stop sprinting
end
end
Character.Humanoid.Running:Connect(function(SpeedValue_4)
SpeedValue_3 = SpeedValue_4
print(SpeedValue_3)
end)
local function IsShiftKeyDown()
return UserInputService:IsKeyDown(ShiftKey)
end
local function Input(input, gameProcessedEvent)
if not IsShiftKeyDown() then
print("NO")
elseif IsShiftKeyDown() and SpeedValue_3 <= 1 then
print("YES")
RunAnimation:Stop()
Running = false
Character.Humanoid.WalkSpeed = SpeedValue_2
CamIn:Play()
CamOut:Pause()
end
end
UserInputService.InputBegan:Connect(Input)
I tried something like this, but function always ‘updates’ when I ‘press’ any button on the keyboard or mouse. I also tried other events like InputEnded, which I thought would work, because when I hold shift and release the button where I’m walking(WASD), it will update and do stuff in the if statement, but it updates when I release another button, after releasing (WASD).
local speed = (character.HumanoidRootPart.Velocity).magnitude;
Getting players speed doesn’t really help me out, because it doesn’t update every time.
If you only want it to update when you press shift then just check the InputObject.KeyCode is equal to shift. What is the end goal here? Are you trying to create a run script?
For example, when I start walking(holding WASD) and then start holding LeftShift, when I release WASD, it does nothing, until I press and release another button (It could be WASD again)
That’s right. The only problem is when I hold LeftShift and run with any of control buttons and when I release any of control buttons again (I’m still holding shift), my character will be in an idle form, but he will still play a run animation.
Here’s another option where you can track which keys are pressed and update the character/whatever you need on RenderStep.
-- Services
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local shiftKey = Enum.KeyCode.Shift
keyDown = {}
-- Local functions
local function inputBegan(input, gameProcessedEvent)
if gameProcessedEvent then return end
if (input.InputType = Enum.UserInputType.Keyboard) then
keyDown[input.KeyCode] = true
end
end
local function inputEnded(input, gameProcessedEvent)
if gameProcessedEvent then return end
if (input.InputType = Enum.UserInputType.Keyboard) then
keyDown[input.KeyCode] = false
end
end
local function updateControls()
if keyDown[shiftKey] then
-- Action here
else
-- Other action here
end
end
-- Connections
UserInputService.InputBegan:Connect(inputBegan)
UserInputService.InputEnded:Connect(inputEnded)
RunService:BindToRenderStep("UpdateControls", 1, updateControls)
I doubt that checking the player speed each frame will affect performance too much, so could you do something like this?
local character = game.Players.LocalPlayer.Character;
game:GetService("RunService").RenderStepped:Connect(function(dt)
-- Check if player is running.
if (character ~= nil) then
local speed = (character.HumanoidRootPart.Velocity).magnitude;
if (speed == 0) then
-- Stop animation.
end
end
end);
Character.Humanoid.Running:Connect(function(SpeedValue_4)
SpeedValue_3 = SpeedValue_4
print(SpeedValue_3)
end)
game:GetService("RunService").RenderStepped:Connect(function(dt)
if (Character ~= nil) then
local SpeedValue_3 = (Character.HumanoidRootPart.Velocity).Magnitude
if (SpeedValue_3 == 0) and Running == true then
Running = false
Character.Humanoid.WalkSpeed = SpeedValue_2
CamIn:Play()
CamOut:Pause()
RunAnimation:Stop()
end
end
end)
This could be the solution, but I still have a tiny question. If I add ‘print(STOP)’ inside the last if statement, it prints it just like in a loop. I’m wondering, does the whole code in the last if statement loops always until I release LeftShift?
Not too sure what you’re asking here. If it checks if Running is equal to true then you set running to false, somewhere else there must also be setting Running to true or else that wouldn’t run.
See: RunService | Documentation - Roblox Creator Hub. Since you are listening to the RenderStepped event, the connected function will fire every frame. So yes, if the “if” condition is hit, it will be entered every frame until you release.
I also recommend using RunService:BindToRenderStep() instead of a connection to RenderStepped.
Using the ContextActionService is a much better idea for binding a function (action) to a specific input like pressing the Shift key.
You can then also listen and act upon the end of input:
local ContextActionService = game:GetService("ContextActionService")
local SHIFT_KEY = Enum.KeyCode.Shift
local function shiftSprint(actionName, inputState, inputObj)
if inputState = Enum.UserInputState.InputBegan and SpeedValue_3 < 1 then
Running = true
Character.Humanoid.WalkSpeed = SpeedValue_1
CamOut:Play()
CamIn:Pause()
RunAnimation:Play()
elseif inputState = Enum.UserInputState.InputEnded and Running then
-- stop running
end
end
ContextActionService:BindAction("ShiftSprint", shiftSprint, false, SHIFT_KEY)
If you ever need to unbind the action use ContextActionService:UnbindAction("ShiftSprint"). Also, I’m not sure how you’re setting SpeedValue_3 but I just copied your conditional statement
Can’t you just check the speed when the player holds shift? I might not understand exactly what you’re saying. Is SpeedValue_3 the speed of the player?
Or if I am understanding correctly wouldn’t it be a better idea to have a isRunning variable but also a isRunAnimation variable to separate the animation from the running itself? This way you can still hold shift without the run animation playing when you’re at a stand still.
Honestly you shouldn’t be using RenderStepped for anything that isn’t a camera update. Especially not in this case. Use Stepped as it fires before physics simulation and is probably what you need, considering Humanoid movement is a physics-based task.
cc @Nucl3arPlays
@RetributionVI
This is highly dependent on the client and there is no guarantee of 60/second frames. Some users can have lower framerates and thus bring down the amount of times per-frame functions are ran.