Animation doesnt play if held shift before running

im making a shift to sprint but the animation doesnt play when i move if i hold shift before moving and if im holding shift and stop moving it keeps playing. im going insane

local Player = game.Players.LocalPlayer;
local Parent = script.Parent;
local Humanoid = Parent:WaitForChild("Humanoid");

local TweenService = game:GetService("TweenService");

local Sprint = Humanoid:LoadAnimation(script:WaitForChild("Sprint"))

local Sprinting = false

game:GetService("UserInputService").InputBegan:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 80
		}):Play();
		Humanoid.WalkSpeed = 23
		if Humanoid.MoveDirection.Magnitude > 0 then
			Sprint:Play(.5)
		end
		Sprinting = true;
	end;
end);

game:GetService("UserInputService").InputEnded:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 70
		}):Play();
		Humanoid.WalkSpeed = 16
		if Humanoid.MoveDirection.Magnitude <= 0 then
			Sprint:Stop(.25)
		end
		Sprinting = false;
	end;
end);

WHat is worng?!?!

InputBegan only fires once every time the player begins an input, same thing goes with InputEnded when the player stops interacting. When you hold shift, the script runs once and checks that you are not moving, and when you start moving, the script won’t run again to check if the player is still moving thus won’t play the animation. For InputEnded, when you hold shift and stop moving, input keycode isn’t left shift but instead w, a, s or d so the animation continues playing without being stopped.
The solution is to set up a Humanoid:GetPropertyChangedSignal(“MoveDirection”) inside InputBegan and play the animation when magnitude is greater than 0 and stop playing the animation when magnitude is equal 0, and disconnect the connection when InputEnded.
Check this if you are not familiar with the function:
https://developer.roblox.com/en-us/api-reference/function/Instance/GetPropertyChangedSignal

2 Likes
humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
	if humanoid.MoveDirection.Magnitude <= 0 then
		--Stop animation track.
	end
end)

This will fix your second issue, if implemented correctly.

Hey. that is basically what im doing

game:GetService("UserInputService").InputBegan:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 80
		}):Play();
		Humanoid.WalkSpeed = 23
		Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			if Humanoid.MoveDirection.Magnitude > 0 then
				Sprint:Play(.5)
			elseif Humanoid.MoveDirection.Magnitude <= 0 then
				Sprint:Stop(.25)
			end
		end)
		Sprinting = true;
	end;
end);

but he said disconnect in Input ended but I dont know how?

game:GetService("UserInputService").InputEnded:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 70
		}):Play();
		
		Humanoid.WalkSpeed = 16
		Sprinting = false;
	end;
end);

Move the snippet into its own code block.

What do you mean by that? Put the whole code?

		Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			if Humanoid.MoveDirection.Magnitude > 0 then
				Sprint:Play(.5)
			elseif Humanoid.MoveDirection.Magnitude <= 0 then
				Sprint:Stop(.25)
			end
		end)

Hey. that is basically what im doing

game:GetService("UserInputService").InputBegan:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 80
		}):Play();
		Humanoid.WalkSpeed = 23
		Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			if Humanoid.MoveDirection.Magnitude > 0 then
				Sprint:Play(.5)
			elseif Humanoid.MoveDirection.Magnitude <= 0 then
				Sprint:Stop(.25)
			end
		end)
		Sprinting = true;
	end;
end);

but he said disconnect in Input ended but I dont know how?

game:GetService("UserInputService").InputEnded:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 70
		}):Play();
		
		Humanoid.WalkSpeed = 16
		Sprinting = false;
	end;
end);

Basically, GetPropertyChangedSignal creates a connection when the MoveDirection property changes, which means if you press shift twice, two connections will be created thus the animation will play and stop twice which might create bugs. How you disconnect connections is by assigning them to a variable and then call :Disconnect()
Example:

local connection = Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
--code here
end)
connection:Disconnect() --this stops the code inside the connection from running again
1 Like

question do i make thisconnecting inside input began? because if i do i cant call it in inputended

Create the connection inside InputBegan, disconnect the connection inside InputEnded. You can make the variable global by removing the “local” before it or create the variable at the top of the script, outside the connections and assign it to the connection.

local connection

game:GetService("UserInputService").InputBegan:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 80
		}):Play();
		Humanoid.WalkSpeed = 23
		connection = Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			if Humanoid.MoveDirection.Magnitude > 0 then
				Sprint:Play(.5)
			elseif Humanoid.MoveDirection.Magnitude <= 0 then
				Sprint:Stop(.25)
			end
		end)
		Sprinting = true;
	end;
end);
1 Like

It worked! thank you. also. the animation glitches badly for some reason?

My bad. The connection wasn’t assigned properly. I just went into studio to check and apparently, you cannot call :Connect() on connections as variables like that.
What you do with this is:

local connection
connection = Humanoid:GetPropertyChangedSignal("MoveDirection")
connection:Connect(function()
--code
end)

connection:Disconnect()
1 Like

i got a disconnect is not a valid member of rbxsscriptsignal

Alright I know now. GetPropertyChangedSignal returns a RBXScriptSignal, RBXScriptSignal:Connection() returns a RBXScriptConnection, we will need 2 variables on that. This should work

local connection

game:GetService("UserInputService").InputBegan:Connect(function(Input, gameProccesed)
	if (Input.KeyCode == Enum.KeyCode.LeftShift) and Parent:FindFirstChild("Humanoid") and Humanoid.Health > 0 and Humanoid.WalkSpeed ~= 0 and not gameProccesed then
		TweenService:Create(workspace.CurrentCamera, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut), {
			FieldOfView = 80
		}):Play();
		Humanoid.WalkSpeed = 23
		local signal = Humanoid:GetPropertyChangedSignal("MoveDirection")
        connection = signal:Connect(function()
			if Humanoid.MoveDirection.Magnitude > 0 then
				Sprint:Play(.5)
			elseif Humanoid.MoveDirection.Magnitude <= 0 then
				Sprint:Stop(.25)
			end
		end)
		Sprinting = true;
	end;
end);
1 Like

Thanks! this works much better. also is the animation buggy because of movedirection magnitude being set to something lower then 1?
Capture

No, it has nothing to do with the magnitude being lower than 1 because it is an approximate value of MoveDirection. The animation is buggy because the InputBegan established multiple connections at once, so when the magnitude is greater than 0, many animations get played at the same time. If you disconnect the connection, it would maintain 1 connection at all times and only 1 animation should play at once.

1 Like

How can I clamp only 1 animation then?

Well, just make sure you don’t play another animation when an animation is already running. Roblox has a pretty nice function for this: Animator:GetPlayingAnimationTracks which returns all current playing animation tracks as an array so you can stop all of them.
Now that I realize, you loaded animation into Humanoid, though this still does work, is not recommended, as loading animations to Animator is much more efficient. An animator is always automatically created inside Humanoid when the character loads.

1 Like