Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

What kind of loop should i use?

i am currently scripting an elevator and i have reached a problem where when a button is clicked and the elevator is in use the button will not work because i have a variable active set to true when the elevator is in use so i would like to know what loop would be useful to use so that when a button is clicked and the elevator is active it will still eventually proceed to run its function after the button is pushed?

some pseudo code of what im dealing with here looks like this

1 button is pushed 2 if active = false continue 3 active = true 4 elevator moves to designated floor 5 active = false 6 else nothing happens 7 end

but if another button is pushed while it is active u will see that it will just not work so how could i possibly troubleshoot this issue that has come up?

2 comments

0

I haven't the faintest idea what you're problem is...

0

i want to know how to make a loop that will wait until the elevator is idle to run

1 answer

✓ Accepted answer

This is a really poorly done question on your part -- You haven't described what you're doing or exactly what you have in mind.


I'm going to assume you have an elevator, and either an "up", "down", and "stop" button, and a "call to this floor" button (maybe a few of these).

That means the elevator has a few states: moving up, moving down, or stopped.

Based on the last button that was pressed, it has a particular state (or we could get more complicated).


At this point, there are two approaches. Since the important state changes are when you press buttons, it might actually be best to not have some constant loop and just do work when the buttons are pressed. This gets a little complicated, but I'll outline it first, because it sometimes looks nice.

The other option is for something to constantly be looking at the elevator's state and make sure it is appropriate based on the last button pressed. I'll do this second.

Events

I'm going to use a "hypothetical" elevator where the only thing I do is set a variable velocity -- 1 for up, -1 for down, 0 for stopped.

function stopButton()
	velocity = 0
end

function upButton()
	velocity = 1
end

function downButton()
	velocity = -1
end

This is remarkably simple -- no loops required.

Now, let's consider a "call" button. For this, we need to know where the elevator is. We'll use y to mean the elevator's position (but we won't set y, only read from it). I'll use ty as the "target y" (the y of the given floor) in this event:

function callTo(ty)
	if ty == y then
		-- You would actually want a small
		-- tolerance, since it probably won't ever be exact
		velocity = 0
	elseif ty < y then
		velocity = -1
	else
		velocity = 1
	end
end

This will make the elevator go towards the floor, but it won't stop when it gets there.

An idiomatic way would be to use a while loop (though a repeat until would be equivalent)

function callTo(ty)
	while ty ~= y do
		-- again, a tolerance would be better
		if ty < y then
			velocity = -1
		else
			velocity = 1
		end
		wait() -- Some pause, to not freeze
	end
	velocity = 0
end

This will work -- but it will only work with 1 call at a time.

One simple solution is the debounce pattern - we essentially "disable" calling as long as it is still going to its floor:

canCall = true

function callTo(ty)
	if not canCall then
		return
	end
	canCall = false -- No one *else* can call
	while ty ~= y do
		--.....
	end
	velocity  = 0
	canCall = true -- Now someone else can call
end

This may be what we want, but it may not. We may want to interrupt the current action whenever we press a button (this would be more sensical to most users, though probably isn't what a real elevator would do)

To do that, we will keep track of something like a reverse debounce, where any other call will inform all previous ones to stop operating.

controller = nil -- which call is controlling the elevator?

function callTo(ty)
	local myControl = math.random()
	-- Or, equivalently, = {}, which I like for succinctness
	controller = myControl
	while controller == myControl and ty ~= y do
		-- .... (same body)
	end
	velocity = 0
end

Now, whenever callTo gets called, it changes controller, but it doesn't change myControl -- so controller == myControl becomes false and the old call stops working.

Single, Constant Loop

The final design that we have is essentially just one loop -- it just gets traded off between different calls to the function with a different ty variable.

With that in mind, we can make a much simpler system:

target = 0 -- ground floor?

function callTo(ty)
	target = ty -- Store most recent call to target
end

while true do
	wait()
	if y == target then
		velocity = 0
	elseif y < target then
		velocity = -1
	else
		velocity = 1
	end
end

This is all we need. If we wanted to put some sort of "debounce", we could do that, too:

target = 0

function callTo(ty)
	target = ty
end

local realTarget = 0
while true do
	wait()
	if y == realTarget then
		velocity = 0
	elseif y < realTarget then
		velocity - 1
	else
		velocity = 1
	end
	if velocity == 0 then
		-- I'm at my floor, so now I can go to the next one
		-- (Maybe also a `wait(1)` in here to stay at the
		-- floor for a least a moment?)
		realTarget = target
		-- Accept the most recent button press.
	end
end

One interesting difference between this and the debounce above is that this will still hear when you press. It just waits until it's done, and then does it. (You could, with the above system, do this by instead repeat wait() until canCall, but this would be a problem if multiple buttons were pressed in that time -- since they might all start more or less at the same time but don't check the debounce -- or, worse, make a big stack of different locations to track to -- so the elevator would be "frozen" in an odd path for however many times people pressed buttons)


Real-er elevator?

I would like to think that real elevators aren't so dumb. I will write more about this shortly.

Here is what I would suggest a real elevator does:

Keeps a list of all floors that need to be visited. A floor needs to be visited because either it was called to that floor, or because that floor was indicated while inside the elevator. I am not going to make any distinction about priority between the two types of calls, though you could if you wanted to.

Whenever a floor that needs to be visited is passed, stop and open the doors -- then continue on.

Here is what it might look like:

-- finds `val` in table `tab`, returning position found
-- warning: false is a valid key.
-- Returns `nil` when not found.
function find(tab, val)
	for i,v in pairs(tab) do
		if v == val then
			return i
		end
	end
end

local visits = {} -- Floors to visit
-- Guaranteed to not contain repeats of any value

function callTo(ty)
	if not find(visits, ty) then
		-- If the list doesn't already contain this target,
		-- then add it.
		table.insert(visits, ty)
	end
end


local target = y -- Ground floor?

while true do
	wait()
	if find(visits, y) then
		-- I'm on a floor that's wanted!
		-- (Thus the elevator will stop on its way rather than
		-- go all the way up then back down to floors in
		-- the middle)

		open = true -- Open doors
		wait(1)
		open = false -- Close doors

		table.remove(visits, find(visits, y))
		-- remove this floor from the list to visit
	end
	if y == target then
		if #visits > 0 then
			target = table.remove(1) -- Attend to oldest first.
		else
			-- No floors to visit. Stop and wait
			velocity = 0
		end
	end
end

4 comments

0

My elevator is extremely realistic if u want to see then here is a link to my place http://www.roblox.com/Building-place?id=205928773

0

this is still alittle confusing on what this script does because I need to know how to combine it with my existing script

0

This is sort of "pseudocode" -- it doesn't do anything on its own (I just set velocity, open; read y, etc which would probably actually be modifying properties of objects or calling functions). It's well explained and fairly simple so you should be able to implement it (or derivations of it) if you know any Lua. Given that you gave no details of what you were working with... If you have

0

ok thank you i thought this was like more actual code than pseudo code and the only confusing part is the first 2 functions at the beginning i haven't really gone into that part of lua yet being a fairly new scripter

This discussion is preserved as it was. New answers, comments, and votes are closed.