MoveTo Tiny NPC

I did not, let me try something.

1 Like

Doesnt change it still broken, what do I do?

1 Like

Welp, im coming back from school so i cant really help you atm. Hopefully someone reaches out to you soon.

Maybe send a screenshot on how the NPC behaves when pathing

see they do not fully touch it and go on to the next one

1 Like

As I said, this is being caused by MoveToFinished’s timeout, at the end of the page there’s a function to prevent this.

local function MoveTo(humanoid: Humanoid, targetPoint: Vector3, andThen: () -> any?)
	local targetReached = false

	-- listen for the humanoid reaching its target
	local connection
	connection = humanoid.MoveToFinished:Connect(function(reached)
		targetReached = true
		connection:Disconnect()
		connection = nil
		if andThen then
			andThen()
		end
	end)

	-- start walking
	humanoid:MoveTo(targetPoint)

	-- execute on a new thread so as to not yield function
	task.spawn(function()
		while not targetReached do
			-- does the humanoid still exist?
			if not (humanoid and humanoid.Parent) then
				break
			end
			-- has the target changed?
			if humanoid.WalkToPoint ~= targetPoint then
				break
			end
			-- refresh the timeout
			humanoid:MoveTo(targetPoint)
			task.wait(6)
		end

		-- disconnect the connection if it is still connected
		if connection then
			connection:Disconnect()
			connection = nil
		end
	end)
end

local Humanoid -- your humanoid
local TargetPos -- your target position

MoveTo(Humanoid, TargetPos, function()
	print("Finished")
end)
2 Likes

How would I implemnt this into my code? Here it is;

function mobHandler.Move(mob, map)
	local humanoid = mob:WaitForChild("Humanoid")
	local waypoints = map.Waypoints
	
	for waypoint = 1, #waypoints:GetChildren() do
		mob.MovingTo.Value = waypoint
		humanoid:MoveTo(waypoints[waypoint].Position)
		humanoid.MoveToFinished:Wait()
	end
	
	mob:Destroy()
	
	map.Base.Humanoid:TakeDamage(humanoid.Health)
end

You could try move to way point

I made a quick function for your iteration;

local function Iterate(humanoid, t: { Vector3 } , n: number?, andThen: any?)
	n = n or 1
	
	assert(n)
	
	if n > #t then if andThen then andThen() end return end -- if all waypoints have been reached
	
	MoveTo(humanoid, t[n].Position, function()
		Iterate(t, n + 1, andThen)
	end)
end

Also, instead of what you’re doing I would opt for an iterative loop using ipairs/pairs, but with your example you could skip this and opt for the function’s recursion.

Iterate(humanoid, waypoints:GetChildren(), 1, function ()
	mob:Destroy()
	map.Base.Humanoid:TakeDamage(humanoid.Health)
end)

Ok i think i found the solution, try making the agent pathfinding width smaller.

See here:
https://developer.roblox.com/en-us/api-reference/function/PathfindingService/CreatePath

(This also implies you change your script to use PathfindingService instead of MoveTo)

So like this?

local function Iterate(humanoid, t: { Vector3 } , n: number?, andThen: any?)
	n = n or 1

	assert(n)

	if n > #t then if andThen then andThen() end return end -- if all waypoints have been reached

	MoveTo(humanoid, t[n].Position, function()
		Iterate(t, n + 1, andThen)
	end)
end

function mobHandler.Move(mob, map)
	local humanoid = mob:WaitForChild("Humanoid")
	local waypoints = map.Waypoints

	Iterate(humanoid, waypoints:GetChildren(), 1, function ()
		mob:Destroy()
		map.Base.Humanoid:TakeDamage(humanoid.Health)
	end)
end

The part: MoveTo(humanoid, t[n].Position, function() errors moveto

Here is the entire code so far;

--By Rjj259_YT
--Main Variables--
local physicsService = game:GetService("PhysicsService")
local serverStorage = game:GetService("ServerStorage")

local mobHandler = {}

local function Iterate(humanoid, t: { Vector3 } , n: number?, andThen: any?)
	n = n or 1

	assert(n)

	if n > #t then if andThen then andThen() end return end -- if all waypoints have been reached

	MoveTo(humanoid, t[n].Position, function()
		Iterate(t, n + 1, andThen)
	end)
end

function mobHandler.Move(mob, map)
	local humanoid = mob:WaitForChild("Humanoid")
	local waypoints = map.Waypoints

	Iterate(humanoid, waypoints:GetChildren(), 1, function ()
		mob:Destroy()
		map.Base.Humanoid:TakeDamage(humanoid.Health)
	end)
end


function mobHandler.Spawn(name, quantity,map)
	local mobExists = serverStorage.mobs:FindFirstChild(name)
	
	if mobExists then
		for i = 1, quantity do
			task.wait(0.5)
			local cloneMob = mobExists:Clone()
			cloneMob.HumanoidRootPart.CFrame = map.Start.CFrame
			cloneMob.Parent = workspace.Mobs
			cloneMob.HumanoidRootPart:SetNetworkOwner(nil)
			
			local movingTo = Instance.new("IntValue")
			movingTo.Name = "MovingTo"
			movingTo.Parent = cloneMob
			
			for i, object in ipairs(cloneMob:GetDescendants()) do
				if object:IsA("BasePart") then
					physicsService:SetPartCollisionGroup(object, "Mob")
				end
			end
			
			cloneMob.Humanoid.Died:Connect(function()
				task.wait(0.5)
				cloneMob:Destroy()
			end)
			
			coroutine.wrap(mobHandler.Move)(cloneMob, map)
		end
	else
		warn("Requested mob does not exist: ", name)
	end
end

return mobHandler

You’ve not declared the MoveTo function shown in this post: MoveTo Tiny NPC - #15 by Sarchyx. It’s also warning because I forgot to change the table’s values typecheck, you can remove it if you want.

t: { BasePart }

It still does it and when it gets to the spot where it turns before hitting it an error:
I also delcared it now:

local function MoveTo(humanoid: Humanoid, targetPoint: Vector3, andThen: () -> any?)
	local targetReached = false

	-- listen for the humanoid reaching its target
	local connection
	connection = humanoid.MoveToFinished:Connect(function(reached)
		targetReached = true
		connection:Disconnect()
		connection = nil
		if andThen then
			andThen()
		end
	end)

	-- start walking
	humanoid:MoveTo(targetPoint)

	-- execute on a new thread so as to not yield function
	task.spawn(function()
		while not targetReached do
			-- does the humanoid still exist?
			if not (humanoid and humanoid.Parent) then
				break
			end
			-- has the target changed?
			if humanoid.WalkToPoint ~= targetPoint then
				break
			end
			-- refresh the timeout
			humanoid:MoveTo(targetPoint)
			task.wait(6)
		end

		-- disconnect the connection if it is still connected
		if connection then
			connection:Disconnect()
			connection = nil
		end
	end)

This is the line:

if n > #t then if andThen then andThen() end return end -- if all waypoints have been reached

1 Like

My bad, when the function calls Iterate() again the humanoid isn’t passed as first argument.

Iterate(humanoid, t, n + 1, andThen)

still doesnt touch

How about you just move the point a bit further.

sometimes charcaters are different size so that would not work for all.

Do you have any scenario where your maps will not be flat? Like perhaps a map with a hill or something?

If your maps are relatively simple or you’re willing to add waypoints before and after hills (and along the hill if the hill is not a straight line) then you could get away with not using Humanoids at all. Humanoids are actually quite expensive and require physical simulation which will generally start to slow a game down after the first 100 or so humanoid characters (pre-optimizations such as disabling most of the humanoid states).

If you are willing to put in more waypoints you can pretty easily use a much faster method such as the TweenService. Here’s an example of how you could do what you’re wanting using the tween service and some recursive CFraming (for smooth turning).
WaypointWalkersExample.rbxl (39.0 KB)

Yeah! I was planning on using tween service just had no idea how to implement it with my code