Why does Heartbeat only trigger swim idle, but PreRender/RenderStepped play full swim animation with Humanoid:Move()?

I’m trying to move a Humanoid in Roblox using Humanoid:Move(Vector3.new(0, -1, 0), false) inside a RunService connection.

When I use RunService.PreRender or RunService.RenderStepped, the Humanoid plays the full swimming animation correctly. Here’s an example:

RunService.PreRender:Connect(function()
	Humanoid:Move(Vector3.new(0, -1, 0), false)
end)

However, if I switch to RunService.Heartbeat, the Humanoid still moves, but only plays the swimming idle animation instead of the actual swimming motion.

Why does this happen? Is there a difference in how these events affect animation evaluation or physics? And is there a way to get the full swimming animation to play while using Heartbeat, or is it necessary to stick with RenderStepped or PreRender for this kind of behavior?

Thanks!

In short, yes stick with those.

This is to do with task schedule sequencing in that the animation transformation is updated prior to physics and applied during. Setting the state on heartbeat skips this step and so default s to idle.

You could try updating the humanoid state and manually move the character model using cframes.
Or manually toggle play the animation on user input outside of a run service event.

1 Like