Run and Walk animation not working when Running in Circles

Hello. I am trying to create a custom animation script. I have gotten idle, walk, and run animations working. My problem is that when the player runs in circles the speed changes sporadically so the walk animation tries to fade in but doesn’t have time to. I have tried using Roblox’s default animate script for reference, but it didn’t seem to help. The script is very hard to understand.

Video of the issue:

(The number being printed constantly is the player’s speed)

Here is my code (sorry if the variable names aren’t great):

local globals = require(game:GetService("StarterPlayer"):WaitForChild("StarterCharacterScripts"):WaitForChild("Globals"))

local anims = {
	-- id becomes a string later on (assetPrefix..id)
	["Walk"] = {
		id = 13254017584, fadeTime = 0.5, weight = 1
	},
	["Run"] = {
		id = 13254077356, fadeTime = 0.5, weight = 1
	},
	["Idle"] = {
		id = 18440213549, fadeTime = 10, weight = 1
	},
}

local char = script:FindFirstAncestorWhichIsA("Model")
local humanoid = char:FindFirstChildWhichIsA("Humanoid")
local animator = humanoid:FindFirstChildWhichIsA("Animator")


local assetPrefix = "rbxassetid://"

local state = "Idle"

if not script:FindFirstChild("Animations") then
	local animFolder = Instance.new("Folder") 
	animFolder.Name = "Animations" 
	animFolder.Parent = script
end

local function getChildrenWhichAre(parent: Instance, className: string)
	local children = {}
	for _, child in parent:GetChildren() do
		if child:IsA(className) then
			table.insert(children, child)
		end
	end
	return children
end

local function convertToAnimTrack(anim): AnimationTrack
	local function convertToAnim(val)
		if type(val) ~= "number" and type(val) ~= "string" then return nil end
		
		local allAnims = getChildrenWhichAre(script.Animations, "Animation")
		for _, v in allAnims do
			if v.AnimationId == val or v.AnimationId == assetPrefix..val then
				return v
			end
		end
		
		return nil
	end
	
	local animationFound = convertToAnim(anim)
	if animationFound then
		anim = animator:LoadAnimation(animationFound)
	end
	
	if anim:IsA("Animation") then
		anim = animator:LoadAnimation(anim)
	end
	return anim
end

for k, anim in pairs(anims) do
	local animFolder: Folder = script.Animations
	
	--check if animation has already been created
	local preMadeAnims = getChildrenWhichAre(animFolder, "Animation")
	local animPreMade = false

	for _, v in preMadeAnims do
		local idCheck = v.AnimationId == assetPrefix..anim.id
		local nameCheck = v.Name == k
		if idCheck or nameCheck then
			animPreMade = true
			if nameCheck and idCheck then
				break
			end
			if idCheck then
				v.Name = k
			end
			if nameCheck then
				v.AnimationId = assetPrefix..anim.id
			end
			break
		end
	end
	if animPreMade == true then
		continue
	end
	
	local newAnim = Instance.new("Animation")
	newAnim.AnimationId = assetPrefix..anim.id
	newAnim.Name = k
	newAnim.Parent = animFolder
	
	--convert id into valid AnimationId
	anim.id = assetPrefix..anim.id
end

local function getAnimProperties(anim: AnimationTrack)
	local animVals = anims[anim.Name]
	if animVals then
		return animVals
	else
		warn("Animation does not exist in anims table")
		return nil
	end
end

local function playAnim(anim, speed)
	for _, v in animator:GetPlayingAnimationTracks() do
		v:Stop()
	end
	
	speed = speed or 1
	anim = convertToAnimTrack(anims[anim].id)
	
	local animVals = getAnimProperties(anim)

	if not anim.IsPlaying then anim:Play(animVals.fadeTime, animVals.weight) end
end


local function onRunning(speed: number)
	print(speed)
	if speed > 0.5 then
		if speed <= globals.WALKSPEED + 0.1 then
			state = "Walk"
			playAnim("Walk", speed/globals.WALKSPEED)
		elseif speed >= globals.SPRINT_SPEED - 0.1 then
			state = "Run"
			playAnim("Run", speed/globals.SPRINT_SPEED)
		end
	else
		state = "Idle"
		playAnim("Idle", 1)
	end
end

humanoid.Running:Connect(onRunning)

Thanks.

2 Likes

Maybe you can try to stop the player from spinning too quickly. This topic seems to solve this issue:

2 Likes

The problem with that solution (for me) is that my game is designed around the movement system. I feel like limiting the players movement would hurt the smooth feeling I’m going for.

2 Likes

I fixed it. All because I have basically no knowledge on animation scripting lol. Turns out every micro-change in speed replayed the animation. All I had to do was create a variable to see the currently playing animation and see if it was equal to the one I am trying to play.

Updates:

New variable:

local playingAnimation = nil

Updated playAnim() function:

local function playAnim(anim, speed)
	if anim == playingAnimation then return end --this line does the check
	
	playingAnimation = anim --[[this changes the playing animation if the animation 
trying to play is a new animation]]--
	
	anim = convertToAnimTrack(anims[anim].id)

	
	speed = speed or 1
	local animVals = getAnimProperties(anim)

	anim:AdjustSpeed(speed)

	for _, v in animator:GetPlayingAnimationTracks() do
		v:Stop()
	end
	anim:Play(animVals.fadeTime, animVals.weight)
end

Thanks for the help though. :+1:

1 Like

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