Multiple issues with holding down keys --- for sprinting and blocking

Making a combat game with sprinting and blocking, but have run into quite a few issues

Sprinting
1 - The sprint animation will not stop after the player runs out of stamina (same for block)
2 - The run triggers when holding the shift even if I’m not moving anywhere
3 - (When using humanoid.MoveDirection.Magnitude as a fix) When I walk first and hold shift afterwards, it works fine. But if I hold shift and then walk afterwards, nothing fires. No animation or stamina depletion
4 - When I let go of any WASD while sprinting, the sprinting is still functioning

Other
When holding any key, I’m able to trigger other actions, such as the sprint while blocking, block while sprinting, melee, etc. The other keys arent blocked out

NOTES:
-All of these issues are mainly with the local script/animation. The server only continues firing for issue #4
-I handle the animations on the client because I assume it should handle faster than the server for most things. I handle the stamina and other values on the server so the client cant exploit them obviously
-Ive read that it may be better to handle animations outside of UserInputService?
-The animations are loops
-Tried using humanoid.MoveDirection.Magnitude > 0 in some ways, only managed to fix issue #2


Here is a snippet of my code:

Local Script

local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
---Attempt to handle things outside of UserInputService. Was off in the video
local isMoving = false
humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
	if humanoid.MoveDirection.Magnitude > 0 and  UserInputService:IsKeyDown(Enum.KeyCode.E) then
		PlayAnimation(Anim, true, 1.8)
		isMoving = true
	elseif humanoid.MoveDirection.Magnitude < 0 then 
		Anim:Stop()
		isMoving = false
	end
end)

---input
UserInputService.InputBegan:Connect(function(input, isTyping)
	if isTyping then return end
	if input.KeyCode == Enum.KeyCode.R then ---block
       if player.Stamina.Value >= 3 then	 
           local Animation = humanoid:LoadAnimation(game.ReplicatedStorage.BlockAnim)
	       Animation:Play()
	       humanoid.WalkSpeed = 3
	       DefaultEvent:FireServer("Block")
        end
	elseif input.KeyCode == Enum.KeyCode.LeftShift then -- sprint
		if player.Stamina.Value >= 3 and humanoid.MoveDirection.Magnitude > 0 then
           local Animation = humanoid:LoadAnimation(game.ReplicatedStorage.SprintAnim)
			Animation:Play()
			DefaultEvent:FireServer("Run")
	    end
    end
end)
UserInputService.InputEnded:Connect(function(input, isTyping)
	if isTyping then return end
	if input.KeyCode == Enum.KeyCode.R then	
		DefaultEvent:FireServer("BlockEnd")
		humanoid.WalkSpeed = 16
		local playingAnimations = humanoid:GetPlayingAnimationTracks()
		for i, v in pairs (playingAnimations) do
			if v.Name == BlockAnim.Name then v:Stop() end
		end
	elseif input.KeyCode == Enum.KeyCode.LeftShift  then	
		DefaultEvent:FireServer("RunEnd")
		humanoid.WalkSpeed = 16
		local playingAnimations = humanoid:GetPlayingAnimationTracks()
		for i, v in pairs (playingAnimations) do
			if v.Name == SprintAnim.Name then v:Stop() end
		end
	end	
end)

Server Script

game.Players.PlayerAdded:Connect(function(player)
	local Stamina = Instance.new("IntValue", player)
	Stamina.Value = 300
	Stamina.Name = "Stamina"
end)
----Receiving event from Local Script and detecting which action
local DefaultEvent = game.ReplicatedStorage.DefaultEvent
DefaultEvent.OnServerEvent:Connect(function(player, Action)
	local character = player.Character or player.CharacterAdded:Wait()
	local humanoid = character:FindFirstChild("Humanoid")
	if playerTable[player.UserId] == nil then
		playerTable[player.UserId] = {
			Blocking = false,
			Running = false,
			UsingStamina = false,
			WalkSpeed = humanoid.WalkSpeed
		}
	end	
	local playerKey = playerTable[player.UserId] 
	humanoid.WalkSpeed = playerKey.WalkSpeed
	if Action == "Block" then
		playerKey.Blocking = true
		playerKey.UsingStamina = true
	elseif Action == "BlockEnd" then
		playerKey.Blocking = false
		playerKey.UsingStamina = false
		humanoid.WalkSpeed = playerKey.WalkSpeed
	elseif Action == "Run" then
		playerKey.Running = true
		playerKey.UsingStamina = true
	elseif Action == "RunEnd" then
		playerKey.Running = false
		playerKey.UsingStamina = false
		humanoid.WalkSpeed = playerKey.WalkSpeed
	end
	
end)
---- Changing the stamina value
Run.Heartbeat:Connect(function()
	for i, v in pairs(game.Players:GetChildren()) do
		if playerTable[v.UserId] then
			local playerKey = playerTable[v.UserId]
			local player = v
			local character = v.Character
			local humanoid = v.Humanoid
			local Stamina = v.Stamina or v.Backpack.Stamina
            if playerKey.Blocking and Stamina.Value > 5 then ---block
				Stamina.Value -= 2	
				humanoid.WalkSpeed = 3
				if Stamina.Value < 0 then 
					Stamina.Value = 0
					playerKey.Blocking = false
					humanoid.WalkSpeed = playerKey.WalkSpeed
				end
			elseif playerKey.Running and Stamina.Value >= 2 then ---run
				Stamina.Value -= 2	
				humanoid.WalkSpeed = 30
				if Stamina.Value < 0 then 
					Stamina.Value = 0
					playerKey.Running = false
					humanoid.WalkSpeed = playerKey.WalkSpeed
				end
			end
		end	
	end
end)

There were a few other things I tried but I don’t want to make this post more convoluted. Really sad that there have been so many issues. Grateful for any help!

2 Likes

So in the first section of the InputBegan loop you are checking if the stamina is greater than or equal to 3.
If it’s less than 3 you aren’t doing anything about it in the InputBegan function.
Also if you are checking to see if the input stopped then why are you setting walkspeed to 16 if the input stopped?

Ah yes youre right. Would it still be fine to handle the animation inside of UserInputService? How would I solve issue 4 where the sprint doesnt trigger by holding shift first and then walking with WASD after?

And I’m setting the walkspeed to 16 so that I’m returning the player back to normal speed since blocking slows you down. I can remove that since the server handles it. There’s a few client-sided scraps I forgot about and this is one of them

I’ve had issues with using UserInputService for controlling complex vehicles like front-end loaders or cranes with WASD as well as other keys for the other functions. Inputs will cut off if you have multiple at the same time (using WASD to control crane rotation as well as moving the trolley in and out, then using Q & E to operate the script, and R & F to raise/lower the cable) will stop one input with the next input). That’s why I looked at this post wondering if there was a solution discussed with it.
I may have to disable the standard WASD VehicleSeat controls by using a standard Seat and UserInputService commands for my case.

Ahh, I see. It’s really unfortunate then

It looks like we probably will have to implement our own manual handler functions that, say, disable the other keys from firing while one has been triggered, or play animations outside the UserInputService

By the way, I tried adding an elseif statement in the UserInputService for when the stamina is less than 3, and it didn’t really do anything. BUT, I did get results when I removed the “and Stamina.Value >= 2 then” on the server. It finally allowed the running to stop after running out of stamina. I’m not sure why it doesn’t work with it.

elseif playerKey.Running and Stamina.Value >= 2 then

It didn’t cancel the animation since there’s nothing that does that, so I added this to the local script:

player.Stamina.Changed:connect(function(value)
	if value < 3 then
		local playingAnimations = humanoid:GetPlayingAnimationTracks()
		for i, v in pairs (playingAnimations) do
			if v.Name == SprintAnim.Name then v:Stop() end
		end		
	end
end)