NPCs that track moving objects

Currently, I’m trying to make an NPC that tracks what moves (like “James” in “Identity Fraud” in Roblox’s game), but once I have the basics of the script, I try to move it. Only the first detected block is tracked without detecting other than the first detected block.
Eventually I want to detect other blocks as well. How can we improve it? Thank you.

local PathfindingService = game:GetService("PathfindingService")

entity = nil
distanceofentity = nil
firstsetup = true
local myoidrootpart = script.Parent:WaitForChild("HumanoidRootPart")
local myhumanoid = script.Parent:WaitForChild("Humanoid")

while wait(0) do
	local childreninworkspace = game.Workspace:GetChildren()
	for i,workchild in pairs(childreninworkspace) do
		if workchild:IsA("Part") or workchild:IsA("MeshPart") or workchild:IsA("UnionOperation") then
			if workchild.Velocity == Vector3.new(0,0,0) then

			else
				local distofchild = (script.Parent.HumanoidRootPart.Position - workchild.Position).magnitude
				if entity == nil and distanceofentity == nil then
					firstsetup = false
					entity = workchild
					distanceofentity = distofchild
				elseif distanceofentity > distofchild and firstsetup == false then
					entity = workchild
					distanceofentity = distofchild
				end
			end
		elseif workchild:IsA("Model") then
			local childrenofworkchild = workchild:GetChildren()
			for i,childchild in pairs(childrenofworkchild) do
				if childchild:IsA("Part") or childchild:IsA("MeshPart") or childchild:IsA("UnionOperation") then
					local childofme = script.Parent:GetChildren()
					for i,v in pairs(childofme) do
						if v:IsA("Part") or v:IsA("MeshPart") or v:IsA("UnionOperation") then
							if not v == childchild then
								if childchild.Velocity == Vector3.new(0,0,0) then

								else
									local distofchild = (script.Parent.HumanoidRootPart.Position - childchild.Position).magnitude
									if entity == nil and distanceofentity == nil then
										firstsetup = false
										entity = childchild
										distanceofentity = distofchild
									elseif distanceofentity > distofchild and firstsetup == false then
										entity = childchild
										distanceofentity = distofchild
									end
								end
							end
						end
					end
				end
			end
		end
	end
	print(entity,", ",distanceofentity)
	if entity == nil then
		
	else
		local path = PathfindingService:CreatePath()
		path:ComputeAsync(myoidrootpart.Position, entity.Position)
		local waypoints = path:GetWaypoints()
		for i, waypoint in pairs(waypoints) do
			myhumanoid:MoveTo(waypoint.Position)
			myhumanoid.MoveToFinished:Wait()
		end
	end
end
1 Like

Instead of assigning entity throughout the loop, you could just spawn a function to move the humanoid when the entity is detected, rather than assigning it to the entity variable, it will run asynchronously from the loop and not halt anything.

dummy code

while wait() do
detect humanoid stuff blah blah
is it the right distance blah blah

declare what the humanoid is here locally
spawn(function()
move the humanoid
this will run without halting the code
end)

end
end
end

This is just a quick way i could think of, this is by no means the best method or such.
This would at least cut out a big chunk of the code and prevent halting, it will also ensure that it always moves the detected entity and not only the last one declared.

2 Likes

Thank you for your reply.
I found improvements in your response, but they are part of the response,

declare what the humanoid is here locally
spawn(function()
move the humanoid
this will run without halting the code
end)

I would like to know more about it if possible.

As an quote from colbert: Friends don’t let friends use spawn.

@OP, I honestly believe using too many loops might cause performance issues, but I’m not 100% sure. There’s too much to explain here, I’ll just spoonfeed.

local PathfindingService = game:GetService("PathfindingService")

local Entity 
local DistanceOfEntity 
local FirstSetup = true
local HRP = script.Parent.HumanoidRootPart
local Hum = script.Parent.Humanoid

while wait(.2) do
	local WorkspaceChildren = game.Workspace:GetChildren()
	
	for _, Child in ipairs(WorkspaceChildren) do
		if Child:IsA('BasePart') then
			if Child.Velocity ~= Vector3.new(0,0,0) then
				local Distance = (HRP.Position - Child.Position).Magnitude
				if not Entity and not DistanceOfEntity then
					FirstSetup = false
					Entity = Child
					DistanceOfEntity = Distance
				elseif DistanceOfEntity > Distance and FirstSetup == false then
					Entity = Child
					DistanceOfEntity = Distance
				end
			end
		elseif Child:IsA("Model") then
			
			local ChildChildren = Child:GetChildren()
			for _, ChildChild in pairs(ChildChildren) do
				if ChildChild:IsA('BasePart') then
					local CharacterChild = script.Parent:GetChildren()
					
					for _, ChildOfCharacter in ipairs(CharacterChild) do
						if ChildOfCharacter:IsA('BasePart') then
							if ChildOfCharacter ~= ChildChild then
								if ChildChild.Velocity ~= Vector3.new(0,0,0) then
									local Distance = (HRP.Position - ChildChild.Position).Magnitude
									if not Entity and not DistanceOfEntity then
										FirstSetup = false
										Entity = Child
										DistanceOfEntity = Distance
									elseif DistanceOfEntity > Distance and FirstSetup == false then
										Entity = Child
										DistanceOfEntity = Distance
									end
								end
							end
						end
					end
				end
			end
		end
	end
	
	print(Entity,", ",DistanceOfEntity)
	
	if Entity then -- Computes path
		local NewPath = PathfindingService:CreatePath()
		NewPath:ComputeAsync(HRP.Position, Entity.Position)
		local Waypoints = NewPath:GetWaypoints()
		for _, Waypoint in ipairs(Waypoints) do 
			Hum:MoveTo(Waypoint.Position)
			Hum.MoveToFinished:Wait()
		end
	end
end

Thank you for your reply. However, the script you modified doesn’t work.

Edit : I’m sorry, it seems that I forgot to copy the latter part of the script.
Moves firmly