I’m struggling to get a movement controller for NPCs that will work well. the NPCs don’t have humanoids in them, but I want to get behavior similar to Humanoid:MoveTo where they walk at a constant velocity. I am using a VectorForce because as far as I know LinearVelocity doesn’t allow other VectorForces to act on the thing it’s applying force to.
so, I went for a velocity PID controller wrapped with a positional one. not great. I’ve spent a good portion of a day and they oscillate like crazy no matter what constants I put in. the rig is massless.
local pve
local ive = 0
self._CheckPos = RunService.Heartbeat:Connect(function(dt)
local curPos = self.Model.PrimaryPart.Position
local curVel = self.Model.PrimaryPart.AssemblyLinearVelocity
local dir = target - curPos
local ve = targetSpeed - dir.Unit:Dot(curVel)
ive += ve * dt
local dve = (ve - (pve or ve)) * dt
local pe = dir.Magnitude
self._VecForce.Force = self.K * pe * (self.P * ve + self.I * ive + self.D * dve) * dir.Unit
if dir.Magnitude <= 2.0 then
self._CheckPos:Disconnect()
end
pve = ve
end)
I have been testing at around 80 studs at 24 studs/s. I tried setting minimum and maximum outputs but that was no dice either.
the strangest part is that it might work perfectly for a minute going back and forth, then suddenly explode using the same path the next time. and when it restabilizes itself, the problem continues to happen until I restart the simulation.
I also tried dropping the PID and just applying a counter force when it reaches the target. same issue.
how can I derive the magnitude of the pushing force that gets it to a certain velocity? using a magnitude of 1000 went somewhere like 29 studs/s, and I’m not sure how that’s related.
is F=mass*(-velocity)/t for t seconds the best way to push it to a stop? I tried that earlier and it was dodgy, but it might have something to do with the previous movement implementation and not the stopping.
edit: unfortunately, though less frequent, ran into the issue again. the rig flew off in a random direction, although I didn’t get the outputs for the force, so I’ll monitor for that again.
to save someone five minutes, the driving force should be targetSpeed^2 + mass * workspace.Gravity * friction. you also might want to apply a limit to the drag force to always be <= the driving force, otherwise you might run into some oscillation issues like I did.
edit: do NOT limit the driving force, that was actually stupid. a better idea is to just multiply both the drag and the driving force before accounting for gravity with a constant k. the controller will fail to run at high speeds if you don’t tone them down a little bit.