Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

NPC runs away from players, but doesn't changes directions when a player is close to it (?)

Hello Developers!

I've made a simple AI which will run away from players using Pathfinding, the issue however that it does indeed work just it doesn't change directions when encountering different players for example, I'm chasing the AI and the AI is almost infront of another player but the AI doesn't try to move around the player rather it just simply rams said player

Script:

--//NPC\\--
local NPC = script.Parent
local Humanoid = NPC.Humanoid
--//Services\\--
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local PathFindingService = game:GetService("PathfindingService")
--//Functions\\--
local function RunAway()
	local Radius = 50
	for _, Player in ipairs(Players:GetChildren()) do
		if Player:IsA("Player") then
			local Character = Player.Character
			local RootPart = Character:WaitForChild("HumanoidRootPart")
			if (RootPart.Position - NPC.HumanoidRootPart.Position).Magnitude < Radius then
				local NewPath = PathFindingService:CreatePath()
				NewPath:ComputeAsync(RootPart.Position, NPC.HumanoidRootPart.Position)
				if NewPath.Status == Enum.PathStatus.Success then
					local Waypoints = NewPath:GetWaypoints()
					for _, Waypoint in pairs(Waypoints) do
						if Waypoint.Action == Enum.PathWaypointAction.Jump then
							Humanoid.Jump = true
						end
						
						Humanoid:MoveTo(NPC.HumanoidRootPart.Position * Vector3.new(10,0,0))
						Humanoid.MoveToFinished:Wait()
					end
				end
			end
		end
	end
end
--//Pathfinding\\--
RunService.Heartbeat:Connect(function()
	RunAway()
end)

1 comment

0

I edited the answer (again). Hope this helps.

1 answer

This is because even though you are looping through all players, only the path away from first player is calculated. Second and subsequent players will not be taken into account, until the humanoid reaches the end of the calculated path.

In practice it will never happen though, as You have connected Your function to the Heartbeat. So by the time the loop reaches second player, another Heartbeat recalculates everything. Heartbeat runs up to 60FPS!

So this script is essentially reverse zombie. As such, NPS must find the NEAREST player, and try to run away from it. To avoid grinding server resources to the ground, I suggest to re-check which player is closest about each second. Then you can adjust it to needs as needed.

Connecting to Heartbeat is an Overkill imho.

EDIT 2: It seems your pathfinding targets are wrong, and I do not know how did it work for you previously. For NPC to run away along the path, you have to choose a specific point on the map during the COMPUTE phase, rather than adjusting the path afterwards.

local currentFollowedRoot

local function RunAway(RootPart)

	local NewPath = PathFindingService:CreatePath()
	NewPath:ComputeAsync(NPC.HumanoidRootPart.Position, NPC.HumanoidRootPart.Position * Vector3.new(10,0,0)) -- adjust the target here

	if NewPath.Status == Enum.PathStatus.Success then

		local Waypoints = NewPath:GetWaypoints()
		for _, Waypoint in pairs(Waypoints) do
			
			if Waypoint.Action == Enum.PathWaypointAction.Jump then
				Humanoid.Jump = true
                        end

			Humanoid:MoveTo(Waypoint.Position) -- this needs to be a waypoint
			Humanoid.MoveToFinished:Wait()
			
			if currentFollowedRoot ~= RootPart then
				return -- break the path, as new player is found
			end

		end

	end 

end


-- periodically find the nearest player
task.spawn(function()
	
	while NPC.Parent do --break the loop when the NPC is destroyed
		
		local Radius = 50
		local nearestRoot
		for _, plr in pairs(Players:GetPlayers()) do
			
			if plr.Character then
				local root = plr.Character:WaitForChild('HumanoidRootPart')
				local magnitude = (root.Position - 
					NPC.HumanoidRootPart.Position).Magnitude
				if magnitude < Radius then
					Radius = magnitude
					nearestRoot = root
				end
			end
		end

		if nearestRoot then
			currentFollowedRoot = nearestRoot
			task.spawn(function() --edit: I forgor to run this in coroutine
				RunAway(nearestRoot)
			end)
		end
		task.wait(1)

	end

end)

EDIT: Added coroutine for the RunAway function, to prevent it from pausing the loop.

EDIT 2: Fixed the pathfind.

1 comment

0

It works, the only issue however is that it doesn't use Pathfinding anymore (Basically, when running away from a player, it doesn't pathfind so if it encounters a wall it will just simply move through it)

This discussion is preserved as it was. New answers, comments, and votes are closed.