NPC animation looks buggy

Hello! I have an NPC that has a walk animation that plays when it…walks. However, the animation looks quite buggy. When the script is disabled though, the animation becomes ok (while the npc is still walking). I’ve checked the animation priority of the animation, and it is movement. What is the problem?

How the animation is supposed to look like:

The buggy animation:

NPC script:

local CollectionService = game:GetService("CollectionService")

local AttackEvent = game:GetService("ServerStorage").Events.Attacked
local TargetFunc = game:GetService("ServerStorage").Events.Target

local NPC = script.Parent
local HRP = NPC.HumanoidRootPart
local Humanoid = NPC.Humanoid
local Animator = Humanoid.Animator
local NPCSpeed = Humanoid.Speed

local AttackAnim = Animator:LoadAnimation(script.Attack)
local WalkAnim = Animator:LoadAnimation(script.Walk)
local IdleAnim = Animator:LoadAnimation(script.Idle)

local Endpoint = workspace.Base.Hitbox.Position
local Damage = 10
local Range = 2
local AttackSpeed = 0.5
local Walkspeed = Humanoid.WalkSpeed

local MoveTask
local LoopTask

local function Wait(Seconds)
	local WaitedTime = 0
	while WaitedTime < Seconds do
		local Delta = game:GetService("RunService").Heartbeat:Wait()
		WaitedTime += NPCSpeed.Value * Delta
	end
end

local function Movement()
	while true do
		Humanoid:MoveTo(Endpoint)
		task.wait(7)
	end
end

local function Loop()
	while true do
		local Target = TargetFunc:Invoke(NPC, Vector3.new(4, 5, Range))
		if Target then
			if MoveTask then
				task.cancel(MoveTask)
				MoveTask = nil
				Humanoid:MoveTo(HRP.Position)
			end
			AttackEvent:Fire(NPC, Target, Damage)
			AttackAnim:Play(0.1, 1, NPCSpeed.Value)
			script.hit_punch_l:Play()
			Wait(AttackSpeed)
		else
			if not MoveTask then
				MoveTask = task.spawn(Movement)
			end
			game:GetService("RunService").Heartbeat:Wait()
		end
	end
end

local function Magnify()
	local AntsLeft = -1
	for _, v in workspace.Enemies:GetChildren() do
		if v:HasTag("Ant") then AntsLeft += 1 end
	end
	Damage = 10 + (3 * (AntsLeft))
	for _, Part in NPC:GetChildren() do
		if Part:IsA("BasePart") then Part.Color = Color3.fromRGB(math.min(38 + (AntsLeft * 30), 255), 38, 38) end
	end
end

NPCSpeed:GetPropertyChangedSignal("Value"):Connect(function()
	local Speed = NPCSpeed.Value
	Humanoid.WalkSpeed = Walkspeed * Speed
	for _, Animation in Animator:GetPlayingAnimationTracks() do
		Animation:AdjustSpeed(Speed)
	end
end)

local RemovedConnection = CollectionService:GetInstanceRemovedSignal("Ant"):Connect(Magnify)
local AddedConnection = CollectionService:GetInstanceAddedSignal("Ant"):Connect(Magnify)

Humanoid.Died:Connect(function()
	game:GetService("ServerStorage").Events.Died:Fire()
	task.cancel(LoopTask)
	RemovedConnection:Disconnect()
	AddedConnection:Disconnect()
	NPC:RemoveTag("Ant")
	if MoveTask then
		task.cancel(MoveTask)
	end
end)

Humanoid.Running:Connect(function(RunSpeed)
	print(RunSpeed)
	if RunSpeed > 0.01 then
		WalkAnim:Play(0.1, 1, RunSpeed/Walkspeed)
		IdleAnim:Stop()
	else
		IdleAnim:Play(0.1, 1, NPCSpeed.Value)
		WalkAnim:Stop()
	end
end)

Magnify()
LoopTask = task.spawn(Loop)

Sorry for the long script, let me know if there is anything you need to know about the script! :\

try changing it to Action. Maybe an animation that has higher priority was playing with the animation so it become buggy.

+you can also disable default animation script if you want to animate it manually

1 Like

looks like you eitehr are activating it every frame or something is overriding it each frame so it plays again. maybe do it in another way?

i think it should be if RunSpeed > 0 but idk if that will make any difference but you should try just in case

The animation looks like being played every frame. To fix this add a check if the animation is playing before playing it,

if WalkAnim.IsPlaying == false then
    WalkAnim:Play()
end

edit: sorry I accidentaly sent too early

Edit 2: now I see that you want to set the speed of the animation based off of the walk speed. Do this using WalkAnim:AdjustSpeed(RunSpeed/Walkspeed).

You should limit the animation speed regardless of how small or large the NPC is. Replace the following “Running” scope:

Humanoid.Running:Connect(function(RunSpeed)
	local clampedSpeed = math.clamp(RunSpeed / Walkspeed, 0.5, 1.5) -- Prevent too fast/slow anim playback
	if clampedSpeed > 0.05 then
		if not WalkAnim.IsPlaying then
			WalkAnim:Play(0.1, 1, clampedSpeed)
		else
			WalkAnim:AdjustSpeed(clampedSpeed)
		end
		IdleAnim:Stop()
	else
		if not IdleAnim.IsPlaying then
			IdleAnim:Play(0.1, 1, 1)
		end
		WalkAnim:Stop()
	end
end)

I realised that the animation affects the triggering of Humanoid.Running. When I disabled the animation from playing, the Humanoid.Running is only triggered once, as in the npc is moving at a constant speed. But when I enabled the animation, the Humanoid.Running is triggered every frame, and the runspeed value it provides varies a lot. Does this have something to do with the npc’s torso turning in the animation? Other npcs I have don’t have their torso turning in their animation, yet with the same code they dont produce the same error.