Issue with this worm-like system?

Hi! I’m having a problem making a worm-like attack for my game, similar to the worm in lethal company that comes up from the ground. I wanted to use a sort of simplified IK or verlet integration-esque system to position each segment after the other as it moves.

The problem is, with each iteration the result gets more and more chaotic until it devolves into a mess.

Video Example


Muted myself for privacy reasons, but what I said was:
“Each iteration gets off by a little bit until eventually it devolves into a mess.”

Here’s the current code, as well as a summary of what I’ve tried:

Code

My thought process:

  • I started off with RunService, but I’m worried the behavior of RunService would mess something up, and a wait() loop works fine.
  • I tried adding waits in between some stuff, concerned that the positions weren’t updating right away when the segment after it was sampling, but that doesn’t seem to be the problem. The waits helped but made it too laggy.
  • I tried making it use :GetPropertyChangedSignal(“Position”) events for each segment’s parent. Same result.

Notes:

  • It’s all anchored + can’t collide.
  • The direction between two segments seems to only return NaN once, at the beginning of the script.
  • The segments are parented to each other in the order they’re positioned it, so they’ll update in order. This also isn’t affecting the result, because without recursing, only the first one updates, as expected.
  • I don’t want to use roblox physics, I want it all math based. Roblox physics are a mess to work with.
  • Currently I think the issue is the positions it’s moving at a time is far too small to be precise from frame to frame, but I have no way of fixing this. This is also why I think the waits were helping, instead of giving it time to update, it was simply letting the positions it needed to move be bigger.
function recursiveUpdate(inst)

	-- position and align
	local newPos = inst.Parent.Position-inst.Parent.CFrame.LookVector*62
	local newDir = (newPos-inst.Position).Unit

	if newDir == newDir then -- check to make sure .Unit result isn't NaN
		inst.CFrame = CFrame.lookAt(newPos,newPos+newDir)

		-- recurse
		for _,inst2 in ipairs(inst:GetChildren()) do
			if inst2:IsA("MeshPart") and inst2.Name == "DuckWormBody" then
				recursiveUpdate(inst2)
			end
		end
	end

end

while task.wait() do
	for _,inst in ipairs(script.Parent:GetChildren()) do
		if inst:IsA("MeshPart") and inst.Name == "DuckWormBody" then
			recursiveUpdate(inst)
		end
	end
end

prettyyyy sure this is exactly what you’re looking for,

I mean if that works then yeah, but I was more just trying to figure out what’s causing it to jitter and mess up more and more.

Thank you anyway! I’ll test when I can.