NoobPath | Easy Pathfinding

Version 1.3

Precise option
Interval option
Improved .Humanoid()'s Jump function

there’s this weird glitch where if the npc chases someone for a few seconds, the npc will stop moving
npc idle.rbxl (146.5 KB)

1 Like

I am dumb, accidentally used “NoobPath.new” in a spot where I should’ve used “NoobPath.Humanoid” lmao

The reason why is because when NoobPath get the monster’s position, it get its primarypart’s position, the rootpart in this case. However, position doesn’t take consideration of the pivot offset. Although the rootpart’s pivot is on the ground, the rootpart’s position is high up in the air due to the monster’s height, while the player character, a normal rig have their rootpart position only a few studs above the ground. Making it impossible to reach.

local function getNearestTarget(npc, root)
	local dist = 1000
	local char

	
		for _, player in pairs(game.Players:GetPlayers()) do
			local vChar = player.Character
			if vChar and vChar:FindFirstChild("Humanoid") and vChar:FindFirstChild("HumanoidRootPart") then
				local vHum = vChar:WaitForChild("Humanoid")
				local vRoot = vChar:WaitForChild("HumanoidRootPart")
				if vHum.Health > 0 then
					local magnitude = (vRoot.Position - root.Position).Magnitude
					if magnitude <= dist then
						dist = magnitude
						char = vChar
					end
				end
			end
		end
	return char
end

local npc = script.Parent

local ServerStorage = game:GetService("ServerStorage")
local NoobPath = require(ServerStorage.NoobPath)
-- you don't need to require Path, NoobPath is already using it

-- Define AgentParams for the NPC
local AgentParams = {
	AgentRadius = 2,  -- Example value
	AgentHeight = 2,  -- Example value
	AgentCanJump = false,
--	AgentJumpHeight = 0, -- Roblox didn't implement this option, it does nothing
--	AgentMaxSlope = 45, -- Roblox didn't implement this option, it does nothing
	Costs = {warning = 1}
}

-- Initialize NoobPath with AgentParams
local Guy, JumpDetectConnection = NoobPath.Humanoid(npc, AgentParams)

local designatedAreasFolder = workspace:WaitForChild("ai_zones")
local designatedParts = {}

-- Collect designated area parts
for _, part in ipairs(designatedAreasFolder:GetChildren()) do
	if part:IsA("BasePart") then
		table.insert(designatedParts, part)
	end
end

-- Function to check if NPC is inside any designated area part
local function isInsideAnyPart(character)
	for _, part in ipairs(designatedParts) do
		local partPos = part.Position
		local partSize = part.Size
		local characterPos = character.HumanoidRootPart.Position

		-- Check if the NPC is within the area of the part
		local xRange = math.abs(characterPos.X - partPos.X) <= partSize.X / 2
		local yRange = math.abs(characterPos.Y - partPos.Y) <= partSize.Y / 2
		local zRange = math.abs(characterPos.Z - partPos.Z) <= partSize.Z / 2

		if xRange and yRange and zRange then
			return true
		end
	end
	return false
end

Guy.Visualize = true
JumpDetectConnection:Disconnect()

-- runservice.stepped/heartbeat/renderstepped is pretty much the same as a loop, don't worry about the change
-- you don't need connections as you just repeat :Run() at a certain interval(ex: 0.1)
-- which is frequent enough
while task.wait(0.1) do
	local target = getNearestTarget(npc, npc.HumanoidRootPart)

	if target then
		local targetRoot = target:WaitForChild("HumanoidRootPart")

		-- Check if NPC is inside any designated area
		if isInsideAnyPart(npc) then
			-- Run towards target within designated areas
			
			-- since you are not checking for trapped, (Timeout != true), there's no need to Jump to unstuck
			-- also idle is just a state, by calling :Run(), idle automatically change to false
			
			Guy:Run(targetRoot)
			print("Ran")

		else
			-- Move directly to the target outside designated areas
			if not Guy.Idle then
				Guy:Stop()
			end
			

			npc.Hunt:MoveTo(targetRoot.Position)
			print("Stopped")
		end

	end
end

I changed ur code a little bit
Version 1.4 will use PivotPosition instead

it still doesnt work, when you touch a wall and go around it, there is a chance where the npc will stop making paths and stop moving

I wish this module would exist earlier when I was making my own Pathfinding NPC using SimplePath. There’s a lot of things that it does well and also not. I’ve already modified a lot of SimplePath source code to fix those shortcomings.

Would you mind getting into detail about how NoobPath is different from SimplePath?

Since I believe that SimplePath already supports non-humanoid and other things similar.

Thank you for making SimplePath better, nonetheless.

Lastly, it would be amazing for this module to support some additional features of the new pathfinding update!

could you please send the new place, so I can test what’s going wrong, or tell me what changes did you make since the previous place you sent. Make sure you used Version 1.4

1 Like

NoobPath have timeout feature, based on the speed(stud/s) of the agent and the distance between the waypoints, it will automatically calculate time required to travel between waypoints. If after that amount of time and the agent still didn’t reach the next waypoint, the Trapped signal will be fired, indicating that the agent is stuck. The Trapped signal also take in consideration of Humanoid:MoveTo() expiring after a certain threshold, firing if it was expired. Compared to SimplePath, it’s way easier to setup custom non-humanoid npcs in NoobPath, all you need is to put the desired functions and signals into the .new() constructor, can use the NoobPath object regularly. NoobPath also adjust waypoints by removing waypoints that are too close to each other, reducing the risk of getting stuck when trying to jump over an obstacle, which happens often in SimplePath. Other than that, it have some minor improvements in terms of delaying pathfinding while the character is in air (simplepath also does this, but more robust). I also added partial path into NoobPath, and there’s another feature called Precise, which prevent the character from continuing to the next waypoint while in air, slower movements but more accuracy for obby. It’s also more neat, with Path state represented by .Idle, a simple boolean. All methods also get autosuggested. NoobPath is basically SimplePath but more convenient, and the performance is only slightly more expensive.

Also if you found things that don’t work well, please give me suggestions.

1 Like

it is the same file i gave before, to do the glitch, just go around the wall and go behind the npc and it will bug the pathfinding

I fixed that in 1.5 (forgot to add the PivotPosition in :Run())

1 Like

Version 1.5

Removed:

Interval: No longer needed due to optimization of the Jump & WaitUntilLanded
Precise: Not great for performance in general, not very useful

New:

fixed a problem with Server’s NetworkOwnership not working on Path Npc sometimes
optimized Jump & WaitUntilLanded
fixed PivotPosition not being used in :Run()

1 Like

I got this error

ReplicatedStorage.NoobPath:172: attempt to index nil with 'Connect'

it says that the error is coming from NoobPath:Activate()

function NoobPath:Activate()
	if Server then
		self.DescendantAddedC = self.Character.DescendantAdded:Connect(function(Item)
			if Item:IsA("BasePart") and Item:CanSetNetworkOwnership() then
				Item:SetNetworkOwner(nil)
			end
		end)
	end
	
     -- ERROR AT THE LINE BELOW
	 self.MoveFinishedC = self.MoveFinished:Connect(function(Success) -- if you are using custom MoveFinished, Fire(true) if successfully reached
		if self.Idle then
			return
		end
		if Success then
			local NextWaypoint = self:GetNextWaypoint()
			if NextWaypoint then
				self:TravelNextWaypoint()
				self.WaypointReached:Fire(self:GetWaypoint(), NextWaypoint)

			else
				self:Arrive()
			end
		else
			self:Stop()
			self.Trapped:Fire("ReachFailed")
		end
	end)
	self.JumpFinishedC = self.JumpFinished:Connect(function()
		self.InAir = false
	end)
end

It seems like you are using constructor .new() without MoveFinished signal given, which is why it caused an error. If you are using Humanoid, try .Humanoid() constructor.

Custom Movement Example (AlignPosition)

local GS = require(workspace.NoobPath.GoodSignal)
local JumpS = GS.new()
local MoveS = GS.new()

local JumpC = JumpS:Connect(function()
	print("JumpFinished")
end)
local MoveC = MoveS:Connect(function()
	print("MoveFinished")
end)

local PrimaryPart = script.Parent.PrimaryPart

local AlignPos = Instance.new("AlignPosition")
AlignPos.Parent = PrimaryPart
local Attachment = Instance.new("Attachment")
Attachment.Parent = PrimaryPart
AlignPos.Attachment0 = Attachment
AlignPos.Mode = Enum.PositionAlignmentMode.OneAttachment
AlignPos.MaxForce = 25000
AlignPos.Responsiveness = 50

local Guy
Guy = require(workspace.NoobPath).new(
	script.Parent,
	{}, -- AgentParams
	function(Pos)
		print("Moved")
		AlignPos.Position = Pos - PrimaryPart.PivotOffset.Position
		
		local Break = false
		local C
		C = Guy.Overide:Connect(function()
			C:Disconnect()
			Break = true
		end)
		
		task.defer(function()
			while not Break and (PrimaryPart:GetPivot().Position - Pos).Magnitude > 2 do
				task.wait()
			end
			if not Break then
				MoveS:Fire(true)
			end
		end)
	end,
	function()
		-- Custom jumping is complex, I won't implement it in this example
		JumpS:Fire()
	end,
	JumpS,
	MoveS
)
Guy.Visualize = true

Guy:Run(workspace.SpawnLocation)

while task.wait(0.1) do
	Guy:Run()
end 

1 Like

Does this mean we should not turn on the new feature, or is the new feature compatible with Noobpath?

Also anyway of having an open source testing place?

Thanks

the new features are compatible, what I mentioned are features NoobPath offer/improvements to SimplePath

Ok, thanks,

what about a testing place, where the npc have different capabilities… like some are fast and smart, some are slow and smart , some are fast and not so smart…

can different NPCs have different things like above?

NoobPath is just Pathfinding service but simplified and improved. What you mentioned are specific behaviors that will require custom logic and has to be implemented by you.

mm ok… seems like it would be cool to have in noobpath…

is there any kind of global debugging that can be turned off and on… like to see what it is doing when testing things out, but being able to toggle it off at other times?

you can turn visualize on, and add connection to the error, jumpfinished, movefinished, overide, trapped, reached, waypoint reached… events to detect what is happening