There is a slight delay when I play animations for the first time, even though I preload them

Hey there,

I have been working on an open world game recently, and I have noticed that when I equip a tool for the first time, the animation is delayed. This only happens once, after the animation has been loaded it is fine, but I am very confused because I preload the animations using PreloadAsync(), but there is still a delay.

Does anyone know what the problem is/what I am doing wrong?

Here is a video of the delay:

Here is my code:

My tool script
local player = game.Players.LocalPlayer
local animations = script.Parent:WaitForChild("Animations", 10)
local animate = require(game.ReplicatedStorage.Modules.Animation)

script.Parent.Activated:Connect(function()
	if script.Parent.Values.Debounce.Value == false then
		game.ReplicatedStorage.RemoteEvents.Tool.UseTool:FireServer(script.Parent)
	end
end)

game.ReplicatedStorage.RemoteEvents.Tool.UseTool.OnClientEvent:Connect(function(tool)
	if tool == script.Parent then
		animate.Animate(player, animations:FindFirstChild("RockUse"))
	end
end)
The animate module script
local module = {}

module.Animate = function(player, anim)
	--local anim = Instance.new("Animation", player)
	--if type(id) == "number" then
	--	anim.AnimationId = "rbxassetid://"..id
	--else
	--	anim.AnimationId = id
	--end
	--anim.Name = game:GetService("MarketplaceService"):GetProductInfo(tonumber(string.split(anim.AnimationId, "//")[2])).Name
	local animator = player.Character:FindFirstChild("Humanoid"):FindFirstChild("Animator")
	for _, v in pairs(animator:GetPlayingAnimationTracks()) do
		if v.Name == anim.Name then
			v:Play()
			return
		end
	end
	local animation = animator:LoadAnimation(anim)
	repeat wait() until animation.Length > 0
	animation:Play()
	return true
end

module.stopAnimationGroup = function(player, anim)
	local animator = player.Character:FindFirstChild("Humanoid"):FindFirstChild("Animator")
	local tracks = animator:GetPlayingAnimationTracks()
	for _, v in pairs(tracks) do
		if string.find(v.Name, anim) then
			v:Stop()
			v:Destroy()
		end
	end
end

module.stopAnimation = function(player, anim)
	local animator = player.Character:FindFirstChild("Humanoid"):FindFirstChild("Animator")
	local tracks = animator:GetPlayingAnimationTracks()
	for _, v in pairs(tracks) do
		if v.Name == anim then
			v:Stop()
			v:Destroy()
		end
	end
end

return module
The preload script

Server Side:

game.Players.PlayerAdded:Connect(function(player)
	
	local assets = {animations={}, sounds={}}

	for _, v in pairs(game:GetDescendants()) do
		if v:IsA("Animation") then
			repeat wait() until v.AnimationId ~= nil
			table.insert(assets.animations, v.AnimationId)
		end
	end

	game.ReplicatedStorage.RemoteEvents.Awake.SendLoadScreen:FireClient(player, assets)
	
end)

Client Side:

local contentProvider = game:GetService("ContentProvider")

game.ReplicatedStorage.RemoteEvents.Awake.SendLoadScreen.OnClientEvent:Connect(function(assets)
	if not type(assets) == "table" then
		return
	end
	
	local amountLoaded = 0
	
	local localAssets = {animations = {}, sounds = {}}
	
	for a, b in pairs(assets) do
		local success, errorMessage = pcall(function()
			for c, d in pairs(b) do
				local success1, errorMessage1 = pcall(function()
					table.insert(localAssets[a], d)
				end)
				--if success1 then
					
				--end
			end
		end)
	end
	
	for a, b in pairs(localAssets) do
		local wait1 = math.random(10, 30)
		local wait2 = math.random(45, 70)
		local wait3 = math.random(90, 100)
		for i = 1, #b do
			local waitTime = 2
			local success, Error = pcall(function()
				contentProvider:PreloadAsync({assets[i]})
				amountLoaded = i
				script.Parent:WaitForChild("MainLoadingScreen").Percent.Text = "Loading "..a..": "..math.floor((amountLoaded/#b)*100).."%"
			end)
			wait(waitTime/100)
		end
		amountLoaded = 0
	end
	
	game.ReplicatedStorage.BindableEvents.FinishedLoading:Fire()
	
	--for i = 1, #assets do
	--	contentProvider:PreloadAsync({assets[i]})
	--	amountLoaded = i
	--	print("Loading animations: "..((amountLoaded/#assets)*100).."%")
	--end
end)

I don’t know if the reason is because I am preloading on the client or something (I have tried on the server but with no difference)

Any help would be greatly appreciated!

1 Like

Roblox studio is still playing their own tool equip animation & if you want an instant equip without an animation leading up to it, it should be fix animation-wise.

For the first issue there are mainy devforum posts about this, the best solution I found was from @KroKey, from this post.

If you want the animation to instant-equip and have no leading up to it I suggest moving the first animation blocks (not sure what they are called), to the first frame.

1 Like

Oh ok, but if I replace the toolnone animation like the solution in the other post was, how can I have it so different tools play the different toolnone animation for that specific tool

that just roblox being roblox there is nothing you can do about it

Oh, I have seen in games such as dawn of aurora that there is no delay for the animations. Is this possible to do, or would it take quite a bit of scripting?

quite a bit of scripting so in my case they do it like they play the animation before equiping the tool so what you can do is add a wait(0.1) before equiping (sorry for bad spelling)

and now you may be wondering that how to do dat? (if u are)
so there is a function called Humanoid:EquipTool() You can use it do it

1 Like

Ah ok, I will try playing the animation before the tool equips

Find the toolnone animation ID and play that instead if the tool has no animation to play.

Else I suggest adding an attribute to every tool called “AnimationId” then have a client-sided script that plays that animationId if it’s valid, if it’s nil or 0 then play the default tool animation.

By the way please mark a post as solution so that no one else will response to this.

1 Like