How to keep creating waypoints without the pathfinding ending, so that it keeps following the player?
Functionality: Any npc with a dinosaurRootPart will follow the player if it’s inside the sphere, which is a hitbox welded to the player initiated only when the player walks.
local script
local player = game.Players.LocalPlayer
local RunService = game:GetService("RunService")
local PhysicsService = game:GetService("PhysicsService")
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local assets = ReplicatedStorage.Assets
local walkSphere = assets["Walk sphere"]
local runSphere = assets["Run sphere"]
local dinosaurMainNPC = workspace:WaitForChild("main NPC2")
local dinosaurWalkToRemote = ReplicatedStorage.dinosaurWalkTo
local weldConstraint1 = Instance.new("WeldConstraint")
weldConstraint1.Part0 = humanoidRootPart
weldConstraint1.Part1 = runSphere
local weldConstraint2 = Instance.new("WeldConstraint")
weldConstraint2.Part0 = humanoidRootPart
weldConstraint2.Part1 = walkSphere
weldConstraint1.Parent = workspace
weldConstraint2.Parent = workspace
walkSphere.CFrame = humanoidRootPart.CFrame
runSphere.CFrame = humanoidRootPart.CFrame
local isCharacterHoldingBreath = false
local sphereType = "none"
local activeSphere = nil
local isPlayerMoving = false
-- detect if the character is walking or running with humanoidDirection
RunService.Stepped:Connect(function()
if humanoid.MoveDirection.Magnitude > 0 then
-- if character is walking
if not isPlayerMoving then -- Only print when state changes
print("player is walking")
isPlayerMoving = true
end
walkSphere.Parent = workspace
sphereType = "walkSphere"
activeSphere = walkSphere
else
if isPlayerMoving then -- Only print when state changes
print("player stopped moving")
isPlayerMoving = false
end
walkSphere.Parent = assets
runSphere.Parent = assets
sphereType = "none"
activeSphere = nil
end
end)
local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {workspace}
overlapParams.FilterType = Enum.RaycastFilterType.Include
local function dinosaurInsideSphere()
-- Return false immediately if no sphere is active
if not activeSphere or sphereType == "none" then
print("No active sphere")
return false
end
-- Also check if the active sphere is actually in workspace
if activeSphere.Parent ~= workspace then
print("Active sphere not in workspace")
return false
end
local foundDinosaurs = {}
local timeElapsed = 0
local connection
local result = nil
local finishedChecking = false
connection = RunService.Heartbeat:Connect(function(deltaTime)
timeElapsed = timeElapsed + deltaTime
-- Double-check the sphere is still valid before using it
if not activeSphere or activeSphere.Parent ~= workspace then
connection:Disconnect()
result = false
finishedChecking = true
return
end
local success, hitParts = pcall(function()
return workspace:GetPartsInPart(activeSphere, overlapParams)
end)
if not success then
print("Error in GetPartsInPart:", hitParts)
connection:Disconnect()
result = false
finishedChecking = true
return
end
for _, part in hitParts do
if part.Name == "DinosaurRootPart" then
local enemyChar = part.Parent
-- Ensure it's a valid character model with a Humanoid
if enemyChar:IsA("Model") and enemyChar:FindFirstChildOfClass("Humanoid") then
foundDinosaurs[enemyChar] = true
end
end
end
if timeElapsed >= 0.3 or next(foundDinosaurs) then
connection:Disconnect()
if not next(foundDinosaurs) then
result = false
else
local dinosaurList = {}
for dinoChar, _ in foundDinosaurs do
table.insert(dinosaurList, dinoChar)
end
result = dinosaurList
end
finishedChecking = true
end
end)
-- Wait until the check is complete
repeat
task.wait(0.01)
until finishedChecking
return result
end
local pathFindingService = game:GetService("PathfindingService")
local path = pathFindingService:CreatePath({})
while true do
task.wait(0.1)
-- Only check for dinosaurs if player is actually moving
if isPlayerMoving and activeSphere then
local dinosaurs = dinosaurInsideSphere()
print("Checking for dinosaurs. Result:", dinosaurs)
if type(dinosaurs) == "table" and #dinosaurs > 0 then
for index, dinosaurNPC in dinosaurs do
print("Following dinosaur:", dinosaurNPC.Name)
dinosaurWalkToRemote:FireServer(dinosaurNPC)
end
else
print("No dinosaurs found")
end
else
print("Player not moving, skipping dinosaur check")
end
end
server script:
(The actual pathfinding here)
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local dinosaurMainNPC = workspace["main NPC2"]
local overlapParams = OverlapParams.new()
overlapParams.FilterDescendantsInstances = {workspace}
overlapParams.FilterType = Enum.RaycastFilterType.Include
-- Detects a hit from the player using GetPartsInPart. Documentation for GetPartsInPart: https://devforum.roblox.com/t/how-do-i-use-getpartsinpart/1555768
local dinosaurWalkToRemote = ReplicatedStorage.dinosaurWalkTo
local pathFindingService = game:GetService("PathfindingService")
local path = pathFindingService:CreatePath({
})
local function dinosaurWalkTo(npc, startingPos, endingPos)
path:ComputeAsync(startingPos, endingPos)
if path.Status ~= Enum.PathStatus.Success then
warn("Failed to compute path for", npc.Name)
return
end
local wayPoints = path:GetWaypoints()
if #wayPoints < 2 then
warn("Too few waypoints for", npc.Name)
return
end
npc.Humanoid.PlatformStand = false
npc.Humanoid:ChangeState(Enum.HumanoidStateType.Running)
local waypoint = 2
local moveToConnection
moveToConnection = npc.Humanoid.MoveToFinished:Connect(function(reached)
if reached and waypoint <= #wayPoints then
waypoint += 1
if wayPoints[waypoint] then
npc.Humanoid:MoveTo(wayPoints[waypoint].Position)
end
else
moveToConnection:Disconnect()
end
end)
npc.Humanoid:MoveTo(wayPoints[2].Position)
end
--dinosaurWalkTo(dinosaurMainNPC, dinosaurMainNPC.HumanoidRootPart.Position, humanoidRootPart.Position)
--dinosaurHumanoid:MoveTo(dinosaurNPC.HumanoidRootPart.Position, humanoidRootPart)
dinosaurWalkToRemote.OnServerEvent:Connect(function(player, dinosaurNPC)
local character = player.Character
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
local dinosaurHumanoid = dinosaurNPC:FindFirstChild("Humanoid")
--dinosaurHumanoid:MoveTo(dinosaurNPC.HumanoidRootPart.Position, humanoidRootPart)
dinosaurWalkTo(dinosaurMainNPC, dinosaurMainNPC.HumanoidRootPart.Position, humanoidRootPart.Position)
end)
Note: You can run the scripts by adding a remotevent named “dinosaurWalkTo” in ReplicatedStorage and any npc(For instance Roblox default Rig) in workspace with a dinosaurRootPart(renamed duplicate HumanoidRootPart of the npc).