This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
gustavowizard's profile picture

Stoping a Loop inside a Function

Started by gustavowizard, 06 July 2014 - 12:53 AM
gustavowizard #1
Posted 06 July 2014 - 02:53 AM
hey guys im trying to stop a loop inside a function(on), using another function (0ff), on the code below:


--- Decorative Sonar by Gustavo Wizard
--- Monitor 2x2, btn API
os.loadAPI("btn")
m = peripheral.wrap("top")
local commandBlock = peripheral.wrap("left")
currentCommand = commandBlock.getCommand()
m.setTextScale(0.5)
m.setBackgroundColor(colors.black)
m.clear()
m.setTextColor(colors.red)
m.setCursorPos(8,2)
m.write("TYPHOON TK-208 SONAR")
term.redirect(m)
m.setTextColor(colors.white)
function fillTable()
btn.setTable("SONAR ON", on, 6,16,20,22)
btn.setTable("SONAR OFF", off,20,30,20,22)
btn.screen()
end
function getClick()
event,side,x,y = os.pullEvent("monitor_touch")
btn.checkxy(x,y)
end

function on()
btn.flash("SONAR ON")
while true do     --- here is what i need to change, this loop must stop when i press the button of the function off 
local image = paintutils.loadImage("r.nfp")
paintutils.drawImage(image,8,4)
sleep(.3)
local image = paintutils.loadImage("r2.nfp")
paintutils.drawImage(image,8,4)
sleep(.3)
local image = paintutils.loadImage("r3.nfp")
paintutils.drawImage(image,8,4)
sleep(.3)
local image = paintutils.loadImage("r4.nfp")
paintutils.drawImage(image,8,4)
commandBlock.setCommand("playsound wizard.sonar_low @a")
commandBlock.runCommand()
sleep(.3)
end
end
m.setBackgroundColor(colors.red)
m.setTextColor(colors.white)
function off()
btn.flash("SONAR OFF")
end
fillTable()
while true do
getClick()
end

http://pastebin.com/0BmmcrEs

can anybody give a hand? thanks!
theoriginalbit #2
Posted 06 July 2014 - 03:31 AM
In Lua there is a keyword break which you can use to exit loops. If you also wish to exit the function at the same time you could also use return. Lua Manual page.
gustavowizard #3
Posted 06 July 2014 - 05:51 AM
yes but where i put it to make it work on the code? i must put some code inside the function off() so it can tell the function on() to stop
Bomb Bloke #4
Posted 06 July 2014 - 06:08 AM
At the moment, your on() function is running a loop that repeats while "true" is true (that is to say, indefinitely).

Instead, how about making it repeat so long as a variable - eg "running" - is true, then allow the off() function to toggle the state of that variable?
gustavowizard #5
Posted 06 July 2014 - 06:57 AM
here is the API im using, from direwolf20; what i need is a way to use the btn.toggleButton function to set the Loop true when its toggle and false when its not, i cant do with repeat to beacuse the in what way wont work i need to use 1 function toggle instead of 2 flash, what i just need to know is how to say like 'if toggle is true then' but still aint found the right code


local mon = peripheral.wrap("top")
mon.setTextScale(1)
mon.setTextColor(colors.white)
local button={}
mon.setBackgroundColor(colors.black)
	
function setTable(name, func, xmin, xmax, ymin, ymax)
   button[name] = {}
   button[name]["func"] = func
   button[name]["active"] = false
   button[name]["xmin"] = xmin
   button[name]["ymin"] = ymin
   button[name]["xmax"] = xmax
   button[name]["ymax"] = ymax
end
function funcName()
   print("You clicked buttonText")
end
	   
function fillTable()
   setTable("ButtonText", funcName, 5, 25, 4, 8)
end	
function fill(text, color, bData)
   mon.setBackgroundColor(color)
   local yspot = math.floor((bData["ymin"] + bData["ymax"]) /2)
   local xspot = math.floor((bData["xmax"] - bData["xmin"] - string.len(text)) /2) +1
   for j = bData["ymin"], bData["ymax"] do
	  mon.setCursorPos(bData["xmin"], j)
	  if j == yspot then
		 for k = 0, bData["xmax"] - bData["xmin"] - string.len(text) +1 do
		    if k == xspot then
			   mon.write(text)
		    else
			   mon.write(" ")
		    end
		 end
	  else
		 for i = bData["xmin"], bData["xmax"] do
		    mon.write(" ")
		 end
	  end
   end
   mon.setBackgroundColor(colors.black)
end
	
function screen()
   local currColor
   for name,data in pairs(button) do
	  local on = data["active"]
	  if on == true then currColor = colors.lime else currColor = colors.red end
	  fill(name, currColor, data)
   end
end
function toggleButton(name)
   button[name]["active"] = not button[name]["active"]
   screen()
end	
function flash(name)
   toggleButton(name)
   screen()
   sleep(0.15)
   toggleButton(name)
   screen()
end
											
function checkxy(x, y)
   for name, data in pairs(button) do
	  if y>=data["ymin"] and  y <= data["ymax"] then
		 if x>=data["xmin"] and x<= data["xmax"] then
		    data["func"]()
		    return true
		    --data["active"] = not data["active"]
		    --print(name)
		 end
	  end
   end
   return false
end
	
function heading(text)
   w, h = mon.getSize()
   mon.setCursorPos((w-string.len(text))/2+1, 1)
   mon.write(text)
end
	
function label(w, h, text)
   mon.setCursorPos(w, h)
   mon.write(text)
end
gustavowizard #6
Posted 07 July 2014 - 08:43 PM
At the moment, your on() function is running a loop that repeats while "true" is true (that is to say, indefinitely).

Instead, how about making it repeat so long as a variable - eg "running" - is true, then allow the off() function to toggle the state of that variable?

i try that dont work, it still stay on the loop and the button dont work to stop it while it is on the loop
Bomb Bloke #7
Posted 08 July 2014 - 01:24 AM
You'd need to implement something like the parallel API to catch clicks while the on() function was running.

But really the whole structure of the script could be reworked to simplify things:

Spoiler
os.loadAPI("btn")

local counter, enabled, myTimer = 1, false
local commandBlock = peripheral.wrap("left")
commandBlock.setCommand("playsound wizard.sonar_low @a")

local m = peripheral.wrap("top")
m.setTextScale(0.5)
m.setBackgroundColor(colors.black)
m.clear()
m.setTextColor(colors.red)
m.setCursorPos(8,2)
m.write("TYPHOON TK-208 SONAR")
m.setTextColor(colors.white)
term.redirect(m)

-- Stick all the images in a table:
local images = {paintutils.loadImage("r.nfp"),paintutils.loadImage("r2.nfp"),paintutils.loadImage("r3.nfp"),paintutils.loadImage("r4.nfp")}

local function on()
	btn.flash("SONAR ON")
	myTimer = os.startTimer(0)
	enabled = true
end

local function off()
	btn.flash("SONAR OFF")
	enabled = false
end

btn.setTable("SONAR ON",   on,  6, 16, 20, 22)
btn.setTable("SONAR OFF", off, 20, 30, 20, 22)
btn.screen()

while true do
	local event, par1, x, y = os.pullEvent()  -- Grab any event.
	
	-- If the monitor was touched, check for button clicks:
	if event == "monitor_touch" then
		btn.checkxy(x,y)
	
	-- Or if our timer expired, and the sonar is active, then:
	elseif event == "timer" and par1 == myTimer and enabled then
		paintutils.drawImage(images[counter], 8, 4)
		myTimer = os.startTimer(0.3)
		
		counter = counter + 1
		
		-- If we drew the last image, then reset the counter and run the command.
		if counter > #images then
			counter = 1
			commandBlock.runCommand()
		end
	end
end
gustavowizard #8
Posted 08 July 2014 - 07:42 PM
You'd need to implement something like the parallel API to catch clicks while the on() function was running.

But really the whole structure of the script could be reworked to simplify things:

Spoiler
os.loadAPI("btn")

local counter, enabled, myTimer = 1, false
local commandBlock = peripheral.wrap("left")
commandBlock.setCommand("playsound wizard.sonar_low @a")

local m = peripheral.wrap("top")
m.setTextScale(0.5)
m.setBackgroundColor(colors.black)
m.clear()
m.setTextColor(colors.red)
m.setCursorPos(8,2)
m.write("TYPHOON TK-208 SONAR")
m.setTextColor(colors.white)
term.redirect(m)

-- Stick all the images in a table:
local images = {paintutils.loadImage("r.nfp"),paintutils.loadImage("r2.nfp"),paintutils.loadImage("r3.nfp"),paintutils.loadImage("r4.nfp")}

local function on()
	btn.flash("SONAR ON")
	myTimer = os.startTimer(0)
	enabled = true
end

local function off()
	btn.flash("SONAR OFF")
	enabled = false
end

btn.setTable("SONAR ON",   on,  6, 16, 20, 22)
btn.setTable("SONAR OFF", off, 20, 30, 20, 22)
btn.screen()

while true do
	local event, par1, x, y = os.pullEvent()  -- Grab any event.
	
	-- If the monitor was touched, check for button clicks:
	if event == "monitor_touch" then
		btn.checkxy(x,y)
	
	-- Or if our timer expired, and the sonar is active, then:
	elseif event == "timer" and par1 == myTimer and enabled then
		paintutils.drawImage(images[counter], 8, 4)
		myTimer = os.startTimer(0.3)
		
		counter = counter + 1
		
		-- If we drew the last image, then reset the counter and run the command.
		if counter > #images then
			counter = 1
			commandBlock.runCommand()
		end
	end
end

son of gun it works! lol thanks man, i see you are familiar with the direwolf20 button API :D/>
when i first look and the code i was like hum its missing some function calls but it happens it was me that dont know enough about it ;)/>