Using :Stop() on a looping animation is delayed

I am trying to make a module that handles tools and lets me play animations on equip, idle, use, etc. I am currently testing it with a localscript as I only need to figure out the animation system for it, I have the animation module setup and only need to add a few things later which I don’t need right now.

When I unequip the tool once the idle has started playing, it doesn’t stop until a few seconds later.

I have tried using a regular AnimationTrack:Stop(), the outcome is the same.
I checked for any possible yields in both the animation module and the localscript with a bunch of print()s, there aren’t any and the threads execute as intended.

When I was bug-fixing I noticed that the delay is tied to the fadeTime property, if it’s 0 then there is no delay (yes this does solve the problem but I want it to fade-out), if it’s 3 then it delays by 3 seconds, etc.

Unequipping a tool with fadeTime set to 1: https://files.catbox.moe/k26tcv.mp4
fadeTime set to 0: https://files.catbox.moe/ycikft.mp4

The animation module:

local module = {}

-- Playing AnimationTracks
module.anims = {}

-- Find AnimationTrack based on id
function module:FindAnim(id: string)
	for index, value in pairs(module.anims) do
		if value ~= id then continue end
		return index
	end
end

-- Run functions from the AnimationTrack events
function module:PlayAnimEvents(eventsTable: {[any]: any}, animTrack: AnimationTrack)
	if not eventsTable or eventsTable == {} then return end

	for name, func in pairs(eventsTable) do
		
		-- Check if the event value is a function
		if typeof(func) ~= "function" then 
			return error("Event " .. name .. " value is a " .. typeof(func) .. ", must be a function.") 
		end
		
		-- Using :Connect() so that if there are multiple of same events they can all fire
		local connection
		connection = animTrack:GetMarkerReachedSignal(name):Connect(func)
		
		-- Disconnect the :GetMarkerReachedSignal() event when the animation ends
		animTrack.Ended:Once(function()
			connection:Disconnect()
		end)
	end
end

-- Play a new animation
function module:PlayAnim(Settings: {[string]: any})
	
	-- Stop function execution if some settings aren't specified
	if not Settings 			then return error("Settings not provided") end
	if not Settings.id 			then return error("No animation Id specified") end
	if not Settings.character 	then return error("No character is specified") end
	
	-- Defaults
	if not Settings.fadeTime 	then Settings.fadeTime = 0.5 end
	if not Settings.weight 		then Settings.weight = 10 end
	if not Settings.speed 		then Settings.speed = 1 end
	if not Settings.priority 	then Settings.priority = Enum.AnimationPriority.Action end
	if not Settings.eventsTable then Settings.eventsTable = {} end

	local humanoid = Settings.character:WaitForChild("Humanoid")
	
	-- Stop animation if it's already playing
	if module:FindAnim(Settings.id) then
		module:StopAnim(module:FindAnim(Settings.id), 0)
	end

	local AnimationInstance = Instance.new("Animation")
	AnimationInstance.AnimationId = Settings.id

	local animator: Animator = humanoid:WaitForChild("Animator")

	local animTrack = animator:LoadAnimation(AnimationInstance)
	animTrack.Priority = Settings.priority
	
	animTrack:Play(Settings.fadeTime, Settings.weight, Settings.speed)
	
	-- Save AnimationTrack
	module.anims[animTrack] = Settings.id
	
	-- I figured if I let the animation instance stay there will be memory leaks so yeah i guess :]
	AnimationInstance:Destroy()
	
	-- Run events
	module:PlayAnimEvents(Settings.eventsTable, animTrack)
	
	-- Remove AnimationTrack from the table once it's ended
	animTrack.Ended:Once(function()
		if not module.anims[animTrack] then return end
		module.anims[animTrack] = nil
	end)
	
	return animTrack
end

-- Stop a playing AnimationTrack(s)
function module:StopAnim(animTrack: AnimationTrack, fadeTime: number)
	-- Check if the provided AnimationTrack is valid
	if not animTrack and typeof(animTrack) ~= "AnimationTrack" then 
		return error("animTrack is a " .. typeof(animTrack) .. ", must be an AnimationTrack.") 
	end
	
	-- Default fadeTime
	if not fadeTime then fadeTime = 0.2 end	
	animTrack:Stop(fadeTime)
	
	-- Remove AnimationTrack from the table
	module.anims[animTrack] = nil
end

return module

The localscript:

local ReplicatedStorgae = game:GetService("ReplicatedStorage")

local animsHandler = require(ReplicatedStorgae.AnimationsHandler)

local character = script.Parent

local function onChildAdded(child)
	if not child:IsA("Tool") then return end
	
	local tool: Tool = child
	
	local equipAnim: AnimationTrack = animsHandler:PlayAnim({
		id = "rbxassetid://127705790732258", 
		character = character,
		fadeTime = 0.5,
	})
	local idleAnim: AnimationTrack
	
	equipAnim.Ended:Once(function()
		if tool.Parent ~= character then return end
		
		animsHandler:StopAnim(equipAnim, 2)
		
		idleAnim = animsHandler:PlayAnim({
			id = "rbxassetid://119734790667969",
			character = character,
			fadeTime = 0
		})
	end)
	
	tool.Unequipped:Once(function()
		if not idleAnim then return end
		
		animsHandler:StopAnim(idleAnim, 1)
	end)
end

character.ChildAdded:Connect(onChildAdded)

Any help would be appreciated, thank you.

1 Like

Tried doing a regular animation script in a different place, it works fine so I think it has something to do with my animation module, I’ll have to check.

I figured it out.

In the animation module, I set the default animation weight to 10. What it should’ve been is just 1, once I did that it was working like I needed it to.

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