Waiting until one or another event happens in a loop

So this is just a question I have been trying to deal with. Is there any way I can make the loop wait until either one of the 2 events (value.Changed or MoveToFinished) happen so it can check to break the loop?

Right now the code just waits until the humanoid.MoveToFinished happens, but I want to make it continue the loop on another event at the same time.

for i, waypoint in pairs(path:GetWaypoints()) do
        if activeID ~= currentID then break end

	hum:MoveTo(waypoint.Position)
	hum.MoveToFinished:Wait() -- or workspace.Value.Changed:Wait()?

end

The script I have (without workspace.Value.Changed) works fine, itā€™s just that it seems pretty unoptimized since this is running every runservice.Stepped leaving many loops not broken and still waiting until it triggers randomly (iā€™ve tested it with a print when the loop breaks, when it does it prints like 56x the message at once, sometimes more, depends on how often the dummy goes through the spots it has walked through already. Simply itā€™s not consistent, doesnt stop right after the activeID changes.), which makes me worry a little and leaves me unsatisfied with it.

3 Likes

I would probably put it into a loop, with a pcall too. Something like this:

repeat
	local _, waitResult = pcall(function()
		return workspace.Value.Changed:Wait() or hum.MoveToFinished:Wait()
	end)
until waitResult
1 Like

:wait() will yield, I donā€™t think this will ever work. (i could be wrong)

Would it make more sense to use :connect() and just call the ā€˜MoveToā€™ code in a function instead?

1 Like

correct me if iā€™m wrong but, wont each :wait() have to yield the code which sort of turns the OR into an AND ?

1 Like

I donā€™t believe so, I am assuming it works similar to the wait() function with the returns.

He said when he puts the ā€˜orā€™ between them he gets an error message. IDK, iā€™ve never tried this.

Here, Iā€™ve made a new function:

function waitForChange()
	local value1Changed = false
	local value2Changed = false
	local function checkValue1()
		value1Changed = true
	end
	local function checkValue2()
		value2Changed = true
	end
	workspace.Value.Changed:Connect(checkValue1)
	hum.MoveToFinished:Connect(checkValue2)
	repeat
		wait()
	until value1Changed or value2Changed
	return
end

--[[
	waitForChange()
	print("Value changed")
]]

Basically, you call the function and it waits for a change and moves on once there is a change.

1 Like

He doesnā€™t get an error message, it just doesnā€™t work for the 2nd one (itā€™s not checked)

You could make a BindableEvent that you fire from both signals and wait on:

for i, waypoint in pairs(path:GetWaypoints()) do
	if activeID ~= currentID then break end

	local combinedSignal = Instance.new("BindableEvent")
	hum.MoveToFinished::Connect(function() combinedSignal:Fire("MoveToFinished") end)
	workspace.Value.Changed:Connect(function() combinedSignal:Fire("ValueChanged") end)

	hum:MoveTo(waypoint.Position)

	local whichSignal = combinedSignal.Event:Wait()

	if whichSignal == "MoveToFinished" then
		-- handle move to finished
	else
		-- handle value changed
	end
end

I didnā€™t test it but that would be the gist of it.

You can make it more complicated if you need things like forwarding the individual eventā€™s arguments to the combined event.

1 Like

Thank you, this worked just right! I havenā€™t ever read up on bindable events so this was a nice thing to learn, might use it in future scripts too.

I just polished it up a little, Iā€™ll leave the code for any future devs to see.

local val = instance.new("StringValue")
local activeID
-- keep in mind this runs every runservice.Stepped from now, this is not the full script
activeID = newproxy() 
val.Value = tostring(activeID) -- triggers val.Changed on previous loops and breaks them
local currentID = activeID
	
for i, waypoint in pairs(path:GetWaypoints()) do
	if activeID ~= currentID then break end

    if i == 1 then 
	else
		hum:MoveTo(waypoint.Position)
		
		local combinedSignal = Instance.new("BindableEvent")
		local conn1 = hum.MoveToFinished:Once(function() combinedSignal:Fire() end)
		local conn2 = val.Changed:Once(function() combinedSignal:Fire() end) --Can also send in arguments for extra steps,
		
		combinedSignal.Event:Wait() --and get them in a variable here!
		
		conn1:Disconnect()
		conn2:Disconnect()
		combinedSignal:Destroy()
    end
end
	
print("completed path")

Now ā€œcompleted pathā€ prints consistently (2-5x at once), just as youā€™d expect. The dummy seems to be moving cleaner? as well.
Hope the instance.new and making connections every .Stepped wont make server performance too bad or something, dunno how those things work. Seems perfectly fine after testing a little though. I can finally rest at peace.

Not a huge deal but also you can move the event creation and the two Connect calls outside of the loop.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.