NPCs stuttering due to making them rotate to target

Alright so im simply making some npcs that look at their target, however for some reason thats causing issues whenever a player is spawned in compaired to the results i get when running it normally. Apparently its being replicated to the client in a jittering motion.

Server result:

Client result:

I have already found the function that causes this problem but as im pretty much a beginner i ran out of ways to fix it myself.

local function LookAtTarget()
	
	if nearestTarget == nil then
		return
	end

	local targetPosition = nearestTarget.HumanoidRootPart.Position

	local rotation = Vector3.new(targetPosition.X, NPC.HumanoidRootPart.Position.Y, targetPosition.Z)
	NPC.HumanoidRootPart.CFrame = CFrame.new(NPC.HumanoidRootPart.Position, rotation)
end
4 Likes

Usually the laggy motion is common for fast moving objects as the server can’t replicate the state of instances to the client quick enough for smooth motion. In this case your NPCs movements are replicating unusually slowly though. Could you share some more information about where your script is located, the rest of your movement code and how your NPCs are set up in the workspace? I can’t really think of any particular reason this might be happening otherwise.

1 Like

Are you setting the rig’s network owner to the server? The jitter is sometimes caused when you haven’t done this.
If you haven’t, all you need to do is use Rig.PrimaryPart:SetNetworkOwner(nil) -- nil = server in a server script.

2 Likes

The NPCs are located inside a folder in the workspace and their script is locates inside the humanoid.

Heres the script for further information:


task.wait(0)
local NPC = script.Parent.Parent
NPC.PrimaryPart:SetNetworkOwner(nil)

local TargetFolder = game.Workspace.Monsters
local Target = nil

local CurrentNearestDistance = math.huge
local distance = 0
local nearestTarget = nil

local LastUpdate = tick()

local FireRange = 125
local FireValue = NPC.CanFire

local DebugValue = game.ServerScriptService.Debug
local DebugPart = nil

--Configurables--

local CooldownTime = 0.5



local function FindNearestEnemy()

	local CurrentTime = tick()

	if CurrentTime - LastUpdate < CooldownTime then
		return
	end

	LastUpdate = tick()

	local Targets = TargetFolder:GetChildren()


	if #Targets == 0 then
		return
	end
	
	local nearestDistance = math.huge
	nearestTarget = nil


	for i = 1, #Targets do
		distance = (NPC.PrimaryPart.Position - Targets[i].PrimaryPart.Position).magnitude


		if distance < nearestDistance and Targets[i].Humanoid.Health ~= 0 then
			nearestDistance = distance
			CurrentNearestDistance = distance
			nearestTarget = Targets[i]
		end
	end
	Target = nearestTarget	
end


local function LookAtTarget()
	
	if nearestTarget == nil then
		return
	end

	local targetPosition = nearestTarget.HumanoidRootPart.Position

	local rotation = Vector3.new(targetPosition.X, NPC.HumanoidRootPart.Position.Y, targetPosition.Z)
	NPC.HumanoidRootPart.CFrame = CFrame.new(NPC.HumanoidRootPart.Position, rotation)
end


NPC.Humanoid.Died:Connect(function()
	wait(5)
	NPC:Destroy()	
end)

while NPC.Humanoid.Health ~= 0 do

	FindNearestEnemy()
	LookAtTarget()

	if DebugValue.Value == true and DebugPart == nil then
		DebugPart = Instance.new("Part")
		DebugPart.Parent = NPC
		DebugPart.BrickColor = BrickColor.random()
		DebugPart.Size = Vector3.new(0.2,0.2,0.2)
		DebugPart.Anchored = true
		DebugPart.CanCollide = false
		DebugPart.CanTouch = false

	elseif DebugValue.Value == false and DebugPart then
		DebugPart:Destroy()
		DebugPart = nil
	end

	if Target and Target.PrimaryPart then

		local MoveToPosition = Target.PrimaryPart.Position + (Target.PrimaryPart.AssemblyLinearVelocity * 4)

		NPC.Humanoid:MoveTo(MoveToPosition)

		if DebugPart then
			DebugPart.Position = MoveToPosition
		end
	end

	if CurrentNearestDistance < FireRange and Target and Target.Humanoid and Target.Humanoid.Health ~= 0 then
		FireValue.Value = true
	else
		FireValue.Value = false
	end

	task.wait(0.25)
end

Yup already done that. I set the PrimaryPart of the NPC to the Server’s network ownership.

Honestly I can’t really think of any reason this might be happening. The only solution I can come up with is to have the server only keep track of each NPCs position and rotation and to load / unload and move NPCs on the client through remote events.

1 Like

The only thing thats causing an issue is the LookAtTarget() function. Other than that everything runs fine.

Is there maybe an alternative way to do this? One that maybe changes just rotation and not position?

Don’t use CFrame to change their rotation… Use constraints. In this case AlignOrientation. Just set Attachment0 to the HumanoidRootPart’s RootRigAttachment, the Mode to OneAttachment and the CFrame to the cframe you’re currently using to rotate the NPC.

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.