NPC MoveTo not working properly when being forced to face a part

  1. What do you want to achieve? Keep it simple and clear!

I’m trying to create a pathfinding AI that is able to maintain a certain distance from the player and back away whilst facing the player when approached

  1. What is the issue? Include screenshots / videos if possible!

When I implement the stare function, the AI movement functions are delayed; instead of backing away smoothly, the AI will periodically stop moving before resuming their movement. Furthermore, the AI pathfinding will become very delayed, taking as long as a second to begin moving toward the player. Both of these issues are resolved when the stare function is disabled.

Video of the issue below

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I’ve tried a few different scripts to rotate the part, all using cframes, I’ve tried to set the network owner of the AI to the server, and I’ve tried running the stare function as a separate script from the rest of the move functions using _G.

Here is the current script I’m using

local Stalker = script.Parent
local RootPart = Stalker.HumanoidRootPart

local PathfindingService = game:GetService("PathfindingService")
local TweenService = game:GetService("TweenService")

for i, v in pairs(Stalker:GetDescendants())do
	if v:IsA("BasePart")then
		v:SetNetworkOwner(nil)
	end
end

--The stalker has the following behavior:
--1) Identify nearest player as the "Target"
--2) If distance from target is greater than 40, follow them until in range
--3) If distance from target is less than 30, walk backwards until in range
--4) If the target is in view and within 100 studs, face them

local function findTarget() --Identifies the closest player and labels them as a target
	local players = game.Players:GetPlayers()
	local maxDistance = 100
	local nearestTarget = nil
	
	for index, player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (target.HumanoidRootPart.Position - RootPart.Position).magnitude
			if distance < maxDistance then
				nearestTarget = target
				maxDistance = distance
			end
		end
	return nearestTarget
	end
end

local function stare() --npc faces target
	local rotateCFrame = CFrame.lookAt(Stalker.HumanoidRootPart.Position, Vector3.new(findTarget().Head.Position.X, Stalker.HumanoidRootPart.Position.Y, findTarget().Head.Position.Z))
	local rotateTweenInfo = TweenInfo.new()
	local tween = TweenService:Create(Stalker.HumanoidRootPart, rotateTweenInfo, {CFrame = rotateCFrame})
	tween:Play()
end

local function canSeeTarget() -- detects whether or not there's a line of sight between the target and the stalker
	local origin = RootPart.Position
	local destinationDir = (findTarget().HumanoidRootPart.Position - RootPart.Position).unit * 100
	local ray = Ray.new(origin, destinationDir)
	
	local hit, pos = workspace:FindPartOnRay(ray, Stalker)
	if hit then
		if hit:IsDescendantOf(findTarget()) then
			return true
		else 
			return false
		end
	end
end

local function getPath() -- creates a path to the target
	local pathParams = {
		["AgentRadius"] = 3,
		["AgentCanJump"] = false,
		["WaypointSpacing"] = 1
	}
	local path = PathfindingService:CreatePath(pathParams)
	
	path:ComputeAsync(RootPart.Position, findTarget().HumanoidRootPart.Position)
	
	return path
end

local function stalkTarget() -- maintain 35 +-5 dist. from target
	local path = getPath()
	local distance = (findTarget().HumanoidRootPart.Position - RootPart.Position).magnitude
	local direction = (findTarget().HumanoidRootPart.Position - RootPart.Position).unit
	
	for index, waypoint in pairs(path:GetWaypoints()) do
		local distance = (findTarget().HumanoidRootPart.Position - RootPart.Position).magnitude
		local direction = (findTarget().HumanoidRootPart.Position - RootPart.Position).unit
		
		if distance > 40 or canSeeTarget() == false then --chase
			Stalker.Humanoid.AutoRotate = true
			Stalker.Humanoid:MoveTo(waypoint.Position)
			Stalker.Humanoid.MoveToFinished:Wait()
			
		elseif distance < 100 and canSeeTarget() == true then --stare
			Stalker.Humanoid.AutoRotate = false
			stare()
			
			if distance < 30 then -- evade
				Stalker.Humanoid:MoveTo(RootPart.Position + direction * -10)
				Stalker.Humanoid.MoveToFinished:Wait()
			end

		else --idle
			Stalker.Humanoid.AutoRotate = true
		end
	end
end

while task.wait() do -- activate AI when target is within range
	findTarget()
	if findTarget() then
		stalkTarget()
	end
end

Solved.
For anyone interested, I ended up using ApplyAngularImpulse instead of CFrames.

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