My game contains a LOT of NPCs spread across a giant map. Previously, I simply used Humanoid:MoveTo()
to control their movement, and that worked fine for fewer humanoids, eventually it became too much for the server to handle.
I decided to redo my NPC system so that it follows this pattern:
-
Server performs a raycast down from a random position offsetting the NPC’s origin.
-
Client detects this information and incrementally moves the NPC toward the given position, using CFrames in a RenderStepped loop.
-
If the NPC is too far above the ground, a ray is created down and the NPC is re-positioned to the floor.
This seems to have worked fine, however I’m worried that raycasting every frame for 300+ objects may be a bit too taxing on the client. Here is my code currently:
function critter:Step(dt)
local movePos = self.model:GetAttribute("MovePos")
if not movePos or self.connections["hide"] then return end
local pivot = self.model:GetPivot()
if ((pivot.Position - movePos)*(Vector3.xAxis+Vector3.zAxis)).Magnitude < self.maxSize then
self:Animate("Walk",false)
return
end
local lookAt = Vector3.new(movePos.X,pivot.Position.Y,movePos.Z)
local translateFactor = pivot.LookVector * self.data.speed * dt
local downRay = workspace:Raycast(pivot.Position+Vector3.new(0,50,0),Vector3.new(0,-100,0),params)
if not downRay then return end
self.model:PivotTo(pivot:Lerp(CFrame.new(downRay.Position+Vector3.new(0,self.size.Y/2,0),lookAt),.1)+translateFactor)
self:Animate("Walk",true)
end
Any help coming up with a better or more performant version of this system is greatly appreciated.