Idle priority animation playing over Action priority animation for a single frame?

I have a spear in my game, and I have 2 animations for it.
Idle, and Attack.
Idle is obviously set to Idle priority.
Attack is set to Action priority.

For some reason I can’t seem to figure out, the Idle animation is winning out against the Attack animation for just a single frame at the begginning when it first plays.

The reason I put this in scripting support is because the animations work fine on their own, but when I put them together with a script they jitter like this, I’m not ruling out the possibility that my script it bad, so here’s that:

local IdleAnim
local SwingAnim = nil
local BlockAnim
local LastSwing = 0
local ClickEvent
local WeaponsOut = false
local Debounce = false
local AttackDebounce = false
local BlockSpeed = 10
local AttackCooldown = 0.4

function IsRunning()
	local MoveDirection = Player.Character.Humanoid.MoveDirection
	return CS.GetState() == "Running" and (MoveDirection - Vector3.new(0, MoveDirection.Y, 0)).Magnitude > 0.1
end

function UpdateSwingStates(Weapon)
	if ClickEvent then ClickEvent:Disconnect() end
	if SwingAnim then SwingAnim:Stop() end
	if IdleAnim then IdleAnim:Stop() end
	
	SwingAnim = Player.Character.Humanoid:LoadAnimation(Weapon.Attack)
	local MaxSwings = Weapon.Swings.Value
	ClickEvent = SwingAnim:GetMarkerReachedSignal("Click"):Connect(function(Number)
		if not WM.Equipped() then return end
		if tonumber(Number) == 1 then LastSwing = tick() end
		if tonumber(Number) >= MaxSwings then
			IdleAnim:Play()
			AttackDebounce = true
			wait(AttackCooldown)
			WM.SetState("Attacking", false)
			CS.SetState("Idle")
			wait(AttackCooldown)
			AttackDebounce = false
		else
			SwingAnim:AdjustSpeed(0)
			spawn(function()
				wait(AttackCooldown)
				if not WM.Equipped() then return end
				if tick() - LastSwing > AttackCooldown then
					IdleAnim:Play()
					SwingAnim:Stop()
					WM.SetState("Attacking", false)
					CS.SetState("Idle")
					wait(AttackCooldown)
					AttackDebounce = false
				end
			end)
		end
	end)
end

function CalculateAnim(Weapon, Shield)
	local State = CS.GetState()
	if State == "Knocked" then
		return
	elseif State == "Casting" then
		-- Need to make this a more WeaponModule oriented thing so that in the future when more thing rely on having the weapon out, it'll be easy to know.
		WM.Unequip()
		WeaponsOut = false
	elseif State == "Running" then
		if Weapon then
			if Shield then
				if WM.Blocking() then
					Player.Character.Humanoid.WalkSpeed = BlockSpeed
					CS.SetState("Blocking")
					return script.ShieldBlock
				else
					return script.Run
				end
			else
				if WM.Blocking() then
					Player.Character.Humanoid.WalkSpeed = BlockSpeed
					CS.SetState("Blocking")
					return script.WeaponBlock
				else
					return script.Run
				end
			end
		end
		if Shield then
			if WM.Blocking() then
				Player.Character.Humanoid.WalkSpeed = BlockSpeed
				CS.SetState("Blocking")
				return script.ShieldBlock
			end
		end
	elseif State == "Idle" then
		if Weapon then
			if Shield then
				if WM.Blocking() then
					Player.Character.Humanoid.WalkSpeed = BlockSpeed
					CS.SetState("Blocking")
					return script.ShieldBlock
				else
					local Anim = Weapon:FindFirstChild("Idle")
					if Anim then return Anim end
				end
			else
				if WM.Blocking() then
					Player.Character.Humanoid.WalkSpeed = BlockSpeed
					return script.WeaponBlock
				else
					local Anim = Weapon:FindFirstChild("Idle")
					if Anim then return Anim end
				end
			end
		end
	end
end

CS.Changed(function(State)
	local Character = Player.Character
	if WeaponsOut then
		if IdleAnim then IdleAnim:Stop() end
		local Weapon = Character:FindFirstChild("Weapon")
		local Shield = Character:FindFirstChild("Shield")
		local Anim = CalculateAnim(Weapon, Shield)
		if Anim then
			IdleAnim = Character.Humanoid:LoadAnimation(Anim)
			IdleAnim:Play()
		end
	end
end)

WM.OnUnequip(function()
	WeaponsOut = false
end)

UIS.InputBegan:Connect(function(Input, IsTyping)
	if IsTyping or Credits.Enabled or Debounce then return end
	local Character = Player.Character
	if Input.KeyCode == KeyBinds.GetBinds()['Spirit Weapons'] then
		Debounce = true
		spawn(function() wait(1.2) Debounce = false end)
		WeaponsOut = WM.Toggle(not WeaponsOut)
		if IdleAnim then IdleAnim:Stop() end
		if WeaponsOut then
			local Weapon = Character:FindFirstChild("Weapon")
			local Shield = Character:FindFirstChild("Shield")
			local Anim = CalculateAnim(Weapon, Shield)
			if Anim then
				spawn(function()
					if Weapon then
						local SavedState = CS.GetState()
						CS.SetState("Equipping")
						local EquipAnim = Character.Humanoid:LoadAnimation(script.Equip)
						EquipAnim:Play()
						wait(0.5)
						if CS.GetState() == "Equipping" then CS.SetState(SavedState) end
					end
					if IdleAnim then IdleAnim:Stop() end
					IdleAnim = Character.Humanoid:LoadAnimation(Anim)
					IdleAnim:Play()
				end)
			end
			if Weapon or Shield then
				WM.SetState("Equipped", true)
				if Weapon then UpdateSwingStates(Weapon) end
			else
				WM.SetState("Equipped", false)
			end
		else
			WM.SetState("Equipped", false)
			WM.SetState("Attacking", false)
			WM.SetState("Blocking", false)
			CS.SetState("Idle") -- Kinda bad, but not really since Idle and Running are very similar anyway.
			if Character:FindFirstChild("Humanoid") then Character.Humanoid.WalkSpeed = game:GetService("StarterPlayer").CharacterWalkSpeed end
			if IdleAnim then IdleAnim:Stop() end
			if BlockAnim then BlockAnim:Stop() end
			if SwingAnim then SwingAnim:Stop() end
		end
	end
end)

Mouse.Button1Down:Connect(function()
	if WM.Blocking() or not WM.Equipped() or AttackDebounce then return end
	local Weapon = Player.Character:FindFirstChild("Weapon")
	if Weapon then
		local AttackSpeed = 1 -- In the future set this to some multiple of the users dexterity.
		WM.SetState("Attacking", true)
		CS.SetState("Attacking")
		if not SwingAnim.IsPlaying then SwingAnim:Play() end
		SwingAnim:AdjustSpeed(AttackSpeed)
		LastSwing = tick()
	end
end)

Mouse.Button2Down:Connect(function()
	if not WM.Equipped() then return end
	WM.SetState("Blocking", true)
	WM.SetState("Attacking", false)
	local Humanoid = Player.Character.Humanoid
	local Weapon = Player.Character:FindFirstChild("Weapon")
	local Shield = Player.Character:FindFirstChild("Shield")
	local Anim = CalculateAnim(Weapon, Shield)
	if SwingAnim then SwingAnim:Stop() end
	if IdleAnim then IdleAnim:Stop() end
	if Humanoid and Anim then BlockAnim = Humanoid:LoadAnimation(Anim) end
	if BlockAnim then BlockAnim:Play() end
end)

Mouse.Button2Up:Connect(function()
	WM.SetState("Blocking", false)
	if WM.Equipped() then
		CS.SetState("Idle")
		local Humanoid = Player.Character.Humanoid
		Humanoid.WalkSpeed = game:GetService("StarterPlayer").CharacterWalkSpeed
		if BlockAnim then BlockAnim:Stop() end
	end
end)

It makes it look jittery, like this:

But I want it to look like this:

Here’s the idle animation for reference:

So a quick recap, for some reason the Idle animation makes the player jitter between Idle and Attack for a single frame when Attack first starts up. I’ve already preloaded Attack, so it’s not an issue of loading.

Does anyone know why this is happening?

Maybe try using FadeTime in AnimationTrack:Play(). That usually smoothens out animation transitions.

1 Like

I just tried that, and it made the left arm attempt to sit in the natural roblox idle animation spot, WHAT!?

I know for a fact that there isn’t a single point in the Attack animation where I tell the left arm to just do nothing.

But for some reason, while fading into the animation the left arm and torso appear to want to go back to the ROBLOX idle animation position???