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.