Pathfinding on Non-Humanoid NPC doesn't work

Hello, so i’ve made a non-humanoid enemy npc. I originally used a Humanoid and it worked fine, but the problem was that it’s movements looked very jittery and weird, the enemy didn’t look like it was floating at all. Now the problem here is that no matter what the Path Status is always NoPath for some reason, so the Hover_To function’s code won’t work. It might be a problem with the AgentHeight or AgentRadius but i tried playing around with those and it didn’t work.

The model itself contains the parts and a root, which is supposed to act like HumanoidRootPart , all the other parts are unanchored, massless and welded to the anchored, unwelded, massless Root using WeldConstraints. The waypoints are 4 small green cubes with no collision and a size of 1, 1, 1. Here is the script (it is a server script inside the Model of the NPC).

--||Core
local Core = require(game:GetService("ReplicatedStorage"):WaitForChild("MSCRIPT_Core"))
local Booleans = Core.Booleans
local Services = Core.Services
--||Variables
local Enemy = script.Parent
local Root = Enemy:WaitForChild("Root")
local Fire = Enemy:WaitForChild("Fire")
--Root:SetNetworkOwner(nil)
local Fire_SFX =Fire.SFX_Fire
local Burst_SFX = Fire.SFX_Burst
local Fire_FX = Fire.FX_Fire
--|Path
local Path_Params = {
	AgentHeight = 4,
	AgentRadius = 2,
	AgentCanJump = false,
}
--|Ray
local Ray_Params = RaycastParams.new()
Ray_Params.FilterType = Enum.RaycastFilterType.Exclude
Ray_Params.FilterDescendantsInstances = {Enemy}
--|Other
local Last_Pos
local Status
local Health = 50
local Speed = 100
local Range = 60
local Damage = 30
--||Functions
local function CanSee_Target(Target)
	local Origin = Root.Position
	local Direction = (Target.HumanoidRootPart.Position - Root.Position).Unit * Range
	local Result = workspace:Raycast(Origin, Direction, Ray_Params)
	--------------------------------------
	if Result and Result.Instance then
		if Result.Instance:IsDescendantOf(Target) then
			return true
		else
			return false
		end
	else
		return false
	end
end
------------------------------------------------------------------------------
local function Locate_Target()
	local Players = Services.Players_SVC:GetPlayers()
	local Max_Distance = Range
	local Nearest_Target
	--------------------------------------
	for __, Player in ipairs(Players) do
		if Player.Character then
			local Target = Player.Character
			local Distance = (Root.Position - Target.HumanoidRootPart.Position).Magnitude
			--------------------------------------
			if Distance < Max_Distance and CanSee_Target(Target) then
				Max_Distance = Distance
				Nearest_Target = Target
			end
		end
	end
	--------------------------------------
	return Nearest_Target
end
------------------------------------------------------------------------------
local function Get_Path(Destination)
	local Path = Services.PathFinding_SVC:CreatePath(Path_Params)
	print(Path.Status)
	--------------------------------------
	Path:ComputeAsync(Root.Position, Destination.Position)
	--------------------------------------
	return Path
end
------------------------------------------------------------------------------
local function Strike(Target)
	local Distance = (Root.Position - Target.HumanoidRootPart.Position).Magnitude
	local Striking = false
	local Damaging = false
	--------------------------------------
	if Distance > 5 and not Striking then
		--Humanoid:MoveTo(Target.HumanoidRootPart.Position)
		Striking = true
		--------------------------------------
		Fire.BrickColor = BrickColor.new("Deep orange")
		Fire_FX.Color = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 170, 0)),
			ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 170, 0))
		}
		--------------------------------------
		local Pos = CFrame.new(Root.Position, Target.HumanoidRootPart.Position)
		Core.Tween(Root, TweenInfo.new(0.5, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {CFrame = Pos})
		--------------------------------------
		task.wait(1)
		--------------------------------------
		Core.RandomPitch_SFX(Burst_SFX)
		--------------------------------------
		local Velocity = Instance.new("LinearVelocity", Root)
		Velocity.Attachment0 = Root.Attachment
		Velocity.VectorVelocity = Root.CFrame.LookVector * 100
		--------------------------------------
		Services.Debris_SVC:AddItem(Velocity, 2)
		--------------------------------------
		task.wait(2)
		--------------------------------------
		Fire.BrickColor = BrickColor.new("Medium blue")
		Fire_FX.Color = ColorSequence.new{
			ColorSequenceKeypoint.new(0, Color3.fromRGB(0, 170, 255)),
			ColorSequenceKeypoint.new(1, Color3.fromRGB(0, 170, 255))
		}
		--------------------------------------
		Striking = false
	else
		if not Damaging then
			Damaging = true
			Target.Humanoid.Health -= Damage
			task.wait(0.5)
			Damaging = false
		end
	end
end
------------------------------------------------------------------------------
local function Hover_To(Destination)
	local Path = Get_Path(Destination)
	--------------------------------------
	if Path.Status == Enum.PathStatus.Success then
		for __, Waypoint in ipairs(Path:GetWaypoints()) do
			Path.Blocked:Connect(function()
				Path:Destroy()
			end)
			--------------------------------------
			local Target = Locate_Target()
			--------------------------------------
			if Target and Target.Humanoid.Health > 0 then
				Last_Pos = Target.HumanoidRootPart.Position
				Strike(Target)
				break
			else
				--[[if Waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				end]]
				--------------------------------------
				if Last_Pos then
					local Pos_Tween = Services.Tween_SVC:Create(Root, TweenInfo.new(2, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {Position = Last_Pos})
					Pos_Tween:Play()
					--------------------------------------
					Pos_Tween.Completed:Wait()
					--------------------------------------
					Last_Pos = nil
					break
				else
					local Pos_Tween = Services.Tween_SVC:Create(Root, TweenInfo.new(2, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {Position = Waypoint.Position})
					Pos_Tween:Play()
					--------------------------------------
					Pos_Tween.Completed:Wait()
				end
			end
		end
	else
		return
	end
end
------------------------------------------------------------------------------
local function Wander()
	local Waypoints = workspace.FLDR_Waypoints:GetChildren()
	local Random_Num = math.random(1, #Waypoints)
	Hover_To(Waypoints[Random_Num])
end
------------------------------------------------------------------------------
while true do
	Wander()
	task.wait(0.25)
end

Bump, i don’t know if it’s allowed for this post or not.

You can always use a humanoid and make it float with animations.

Well you see that’s the problem… the enemy isn’t really a humanoid type character, it’s just a floating rock thingy.

I’m pretty sure tween service doesnt work on constraints but I could be wrong.

You can still add a humanoid to it to allow for pathfinding to work

I already said why i don’t want to use humanoids in the post.

Okay, well then you should use the tweenservice because a humanoid is the only way for pathfinding to work

I am indeed using TweenService tho.

I am still having this issue btw.

Is it possible to share the script (rbxl) with us, so we can repo on our end . Based on the script you shared it should give you the path unless there is something wrong elsewhere. You can DM me the file (rbxl) incase you dont want to share with all.

Enemy_AI.rbxm (4.3 KB)
Here, but keep in mind that there are some parts that use functions that they get from a module called “Core”, so idk if i should send you the module as well or not.

Just incase it help others , the issue here is that the non humanoid NPC is at a certain height and when the compute async is called then the position of the NPC is above the ground. Since agentCanJump is false , it can’t generate a Path.

Also the Get_Path should change to

local function Get_Path(Destination)
	local Path = Services.PathFinding_SVC:CreatePath(Path_Params)
	-- Move the print down
	--------------------------------------
	Path:ComputeAsync(Root.Position, Destination.Position)
    print(Path.Status)
	--------------------------------------
	return Path
end

Ok, i did what you said and it actually works. But there’s a problem, since i want to TWEEN the model towards the waypoint, i have to use CFrame (because the model is welded), and it keeps on giving me errors with this line :

local Pos_Tween = Services.Tween_SVC:Create(Root, TweenInfo.new(2, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {CFrame = Waypoint.CFrame})

Instead of passing Cframe (Waypoint does not have CFrame) ,can you pass position (Waypoint.Position)

Yes but as i said, the model is welded together, and for some reason tween service can only tween models with rigs using CFrame, it doesn’t work with position

Just a quick simple little bump.