This moves the NPC with a server side script. However the “movement” is jittery, especially on higher ping. Is there a way to make it smoother? Like a interpolation or something?
local function MovePet(player, pet)
local lastTime = tick()
local speed = 1.5 -- Adjust speed as needed
local function onHeartbeat()
local currentTime = tick()
local deltaTime = currentTime - lastTime
lastTime = currentTime
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and pet.PrimaryPart then
local playerPosition = player.Character.HumanoidRootPart.Position
local offset = Vector3.new(5, 3, 5)
local newPosition = playerPosition + offset
-- Interpolate the pet's position towards the new position with delta time
local currentPos = pet.PrimaryPart.Position
local newPos = currentPos:Lerp(newPosition, speed * deltaTime)
pet:SetPrimaryPartCFrame(CFrame.new(newPos))
-- Calculate the new rotation for the pet
local lookRotation = CFrame.new(pet.PrimaryPart.Position, playerPosition)
local initialRotationOffset = CFrame.Angles(0, math.rad(-90), 0)
lookRotation = lookRotation * initialRotationOffset
-- Set the pet's rotation directly
pet:SetPrimaryPartCFrame(lookRotation)
end
end
-- Connect to Heartbeat event
local connection
connection = game:GetService("RunService").Heartbeat:Connect(function()
onHeartbeat()
end)
Check the documentation for more detailed information, available here
Brief summary of network ownership
Roblox attempts to distribute the physics computation between the server and the clients. This means that clients can be assigned physically simulated assemblies, or groups of BasePart instances, to divide the work of the physics step between the server and connected clients.
That’s why, for example, if you’ve ever tried to move an unanchored sphere between more than one player in Roblox:
It will be more responsive for whoever owns that instance at that point in time because they’re not awaiting packets from the server to update the transform of the instance, and they don’t have to send their packet off for the action to take effect
If you don’t have network ownership of the assembly and experience latency, you’ll note that the instance will move unexpectedly in an attempt to resync the instance on your client
All server-owned, unanchored assemblies are subject to this; but you can toggle the behaviour by using the ::SetNetworkOwner method and setting the assembly’s network owner to nil.
Setting network ownership of the assembly’s root part, or the pet’s HumanoidRootPart in your case, would ensure that the server maintains network ownership of the assembly - this stops it from transferring between players, which can be a source of desync.
The other thing to consider, would be to set the network ownership of the pet to the client that owns it, and then updating the location of the pet on the client. Any changes the network owner would make to its transform, e.g. in the case of your attached script, would be replicated to the server and then sent to the other clients.
Caveat: This does not work on anchored parts, since anchored parts are always owned by the server.