Is there a way to cancel `Humanoid.MoveToFinished:Wait()` in a loop?

Hello! I have a glitchy bug and it was fixed to a level where it wasn’t as glitchy.

What I have right now:

As you can see it’s fairly glitchy what I’m trying to achieve is:

Code:

Mouse.Button2Down:Connect(function()
	local Target = Mouse.Target
	local Character = Player.Character
	
	if Character and Character.PrimaryPart then
		if Target:IsDescendantOf(workspace.World.mapAssets) then
			visualRing() -- Visuals
			
			local path = PathfindingService:CreatePath()
			path:ComputeAsync(Character.PrimaryPart.Position, Mouse.Hit.Position)
			local waypoints = path:GetWaypoints()
			updatePath:Fire()
			local blockedPathEvent
			
			blockedPathEvent = path.Blocked:Connect(function()
				blockedPathEvent:Disconnect()
				updatePath:Fire() -- Basically stops the movement
			end)
			
			spawn(function()
				local stop = false
				local listener 
				
				listener = updatePath.Event:Connect(function()
					Character.Humanoid:MoveTo(Character.HumanoidRootPart.Position)
					listener:Disconnect()
					stop = true
					for _, point in Pairs(workspace.visualAssets.pathPoints:GetChildren()) do
						point:Destroy()
					end
				end)
				
				--generateVisualPath(waypoints)
				for index, waypoint in Pairs(waypoints) do	
					if stop then
						break
					end
					--spawn(function()
						Character.Humanoid:MoveTo(waypoint.Position)
						Character.Humanoid.MoveToFinished:Wait()
					--end)
				end
			end)
		end
	end
end)

Please note that the spawn function which moves the character is commented out because it does somewhat achieve what I want to be shown in the second gyazo. The only issue is then pathfinding no longer works.

I’d assume the issue is with Humanoid.MoveToFinished:Wait() which I would like a way to disconnect it somehow or remove it because at the same time I want the Humanoid.MoveToFinished:Wait() to apply to the loop and don’t.

Any feedback is appreciated

2 Likes

I’m a bit confused why what the actual issue is, but have you thought about maybe about getting the distance between the character’s current location and the target location, then determine to see if the character is within range of it?? With doing this, you have more flexibility so you could break out of that loop at any time.

1 Like

The issue is fairly simple but hard to find a solution:

I have a loop:

for i = 1, 10 do

end

I’m moving a humanoid to a position based ON the loop:

for i = 1, 10 do
Humanoid:MoveTo(Vector3.new(i,i,i))
end

Now I want the character to move to a spot then move to the next one so I add this:

for i = 1, 10 do
Humanoid:MoveTo(Vector3.new(i,i,i))
Humanoid.MoveToFinished:Wait() -- this pauses the loop and waits for the humanoid to finish moving
end

But now I want to stop the loop at a certain point:

local stopMoving = false

bindable.Event:Connect(function() -- so when I want to update I fire this 
stopMoving = true -- set stop moving to true
end)

for i = 1, 10 do
if stopMoving then
break -- this will end the script if stop moving is true
end
Humanoid:MoveTo(Vector3.new(i,i,i))
Humanoid.MoveToFinished:Wait() -- this pauses the loop and waits for the humanoid to finish moving
end

So everything seems fine what’s wrong?

Well, when I move the character the loop stops at Humanoid.MoveToFinished:Wait(). meaning though I may change the stop to true it will have to wait until the humanoid finishes moving once. So my question is how would I be able to disable Humanoid.MoveToFinished:Wait() and at the same time apply it to the loop.

1 Like

I think you could change that out for a repeat block.

repeat wait() until (stopMoving or OtherCondition)

Still not exactly sure what you need, as my comprehension is poor. But, from my understanding, this should fix your issue.

I got an idea from that thank you! I will let you know If I manage to fix it :slight_smile:

1 Like

You can’t ever cancel RBXScriptSignal:Wait() as it yields until the signal fires and obviously developer code is unable to fire such signals.

I see thank you very much but I think instead of something that yields such as a event:Wait() I’d use a different approach like repeat wait() as I can definitely check for conditions like so.

Welp I came up with something but unfortunately it didn’t work as well, it seems as if it was glitching even more :laughing:. Thanks for trying to help though

I’d suggest against using repeat wait() until true for the fact that it’s inefficient. Event based programming is almost always favourable.

What you could do, is each time you call MoveToFinished:Wait(), assign a variable such as "moveId’. This way, if you had multiple MoveToFinished events yielding, you could check that the current moveId is equal to the latest moveId. Here’s an example

local latestMoveId
local function Move(to)
    local thisMoveId = elapsedTime() -- you can use anything as an ID, I like to use elapsedTime() as it guarantees no duplicates in this session (tick() would produce the same desired result)
    latestMoveId = thisMoveId
    humanoid:MoveTo(to)
    humanoid.MoveToFinished:Wait()
    if latestMoveId == thisMoveId then
        -- this will only run on the most 'up to date' MoveToFinished event.
    end
end

This will still cause the events to stack up, using more memory (likely not notable unless you were calling Move a LOT), however it will ensure only the latest Move() call will run beyond the MoveToFinished event!

I’ve having a little trouble understanding here, could you tell me what happens if latestMoveId == thisMoveId then? I don’t see actually solving the problem either because again the statement will run after the humanoid finishes moving to a point since it yields and we will still have to wait.

Oh, perhaps I misunderstood the question here. My example would solve the problem of stacking up :MoveTo/.MoveToFinished events, but I think your issue is different, my mistake.

Are you able to provide a place file where we could replicate this problem? It would be a lot of help if we could experiment with it!

Would you like to contact me via Discord? I can provide details there

Discord: Mystifine#4924

You could skip using humanoid.MoveToFinished:Wait() all together. Create your own condition for finishing the move and that would allow you to break wait loop however you like. When I wrote my NPC AI I used MoveTo with my pathfinding functions and found the MoveToFinished caused me problems. I simply wrote a check to detect when the NPC got close enough to the position and ended the MoveTo or switched to MoveTo a different position. Could be an option for you to do it this way.

I did happen to do so like so:

local canMove = true
local stop = false

stopBindable.Event:Connect(function()
stop = true
end)

for i = 1, 10 do -- exaample loop
local event
event = Hum.MoveToFinished:Connect(function() -- since this won't yield
event:Disconnect()
canMove = true
end)

repeat wait() until stop or canMove do end -- this was my way but it was still jittering

end

Unfortunately it was glitchy when moving to points

I put my MoveTo in a repeat (since it stops after 8 secs) and had it repeat until the NPC position was within “X” studs of goal position. If you play the distance value a bit you can get it to follow a path without glitch hopping.

I’m not sure how you did that could you show some examples? It sounds you you didn’t use pathfinding if u repeated until an NPC position was X studs of aa goal position.

I used the built in pathfinding service only to generate waypoints. After than I use a custom function to apply the MoveTo.

something like this:

repeat
    wait()
    NPC.Humanoid:MoveTo(myPos)
until (NPC.HumanoidRootPart.Position - myPos).Magnitude <= 5

To be honest I find that fairly inefficient (as it can mess up the path if your humanoid agent sizing differs which mine does) and the method is fairly similar to what I’ve done so I doubt that will remove it. Thanks for trying though.

Np, I will say though that it works quite well for me. My NPCs can go anywhere and they do it smoothly. I also adjust the distance based on what speed they are traveling. I’m sure you could do the same for size.