Coroutines Help

How do I get coroutine.yield() to pause for a certain amount of time, let’s say 3 secs for this example, then after 3secs it prints print(“test ended”)

 function setup()
    co = coroutine.create(CoRoutineTest)
    print(coroutine.resume(co))
end

function draw()
    coroutine.resume(co)
end

function CoRoutineTest()
    print("test started")
    coroutine.yield()
    print("test ended")
    
    end

Maybe I’m asking the wrong question. I thought there was a easy way to specify how long I wanted the yield to be but guess not. I know I can use a tween.delay. I’m trying to become adept with coroutines.

 function setup()
    co = coroutine.create(CoRoutineTest)
    print(coroutine.resume(co))
end

function draw()
    coroutine.resume(co)
end

function CoRoutineTest()
 
    print(ElapsedTime)
    print("test")
    coroutine.yield()
    tween.delay(3, function()
    print("testended")
        end)
    end

Coroutines are awesome! I use them a lot, and I have to look up the detail of how to use them every single time.

I think this does what you want.

-- CoroutineExample

function setup()
    co = coroutine.create(CoRoutineTest)
    parameter.watch("coroutine.status(co)")
end

function draw()
    background(40,40,50)
    local th = coroutine.status(co)
    if th ~= "dead" then
        local _,t =  coroutine.resume(co)
        text("running at " .. t,WIDTH/2,HEIGHT/2)
    else
        text("ended",WIDTH/2,HEIGHT/2)
    end
    

end

function CoRoutineTest()
    print("test started")
    local stime = os.clock()
    while os.clock() < stime + 3 do
        coroutine.yield(os.clock())
    end
    print("test ended")
    return os.clock()
end

Feel free to ask about them! Maybe if I can explain them to someone else then I have half a chance of understanding them myself.

@LoopSpace Thanks! That’s exactly what I wanted.

@LoopSpace thanks again. I worked on coroutines for hours today and gained a good understanding. This code is random but shows what I know is possible with them. LoopSpace what do you use coroutines for? Anybody is welcome to answer this 2nd question. How can coroutines help me in making games?

My random coroutine progress for the day

function setup()
    co3 = coroutine.create(CoRoutineTest)
    parameter.watch("coroutine.status(co3)")

   co = coroutine.create(function()
        for i = 1, 10, 1 do
            print(i)
            print(coroutine.status(co))
            if i == 5 then coroutine.yield()      
            end
        end
    end)

print(coroutine.status(co))
    
    co2 = coroutine.create(function()
        for i = 101, 110, 1 do
        print(i)
        if i == 110 then 
            print("i equals 110")
                oneten=true
            end       
    end
end)
end
        
function draw()
    background(40,40,50)
    local th = coroutine.status(co3)
    if th ~= "dead" then
        local _,t =  coroutine.resume(co3)
        text("running at " .. t,WIDTH/2,HEIGHT/2)
    else
        text("ended",WIDTH/2,HEIGHT/2)
    end
    if r==true then
        sprite(asset.builtin.Planet_Cute.Rock,WIDTH/2+300,HEIGHT/2)
        coroutine.resume(co)
           
        tween.delay(3, function()
    print("testended")
            coroutine.resume(co2)
        end)
end
        if oneten == true then
        sprite(asset.builtin.Blocks.Rock,300,300)
    end    
end

function CoRoutineTest()
    print("test started")
    local stime = os.clock()
    while os.clock() < stime + 3 do
        coroutine.yield(os.clock())
    end
    print("test ended")
    r=true
    return os.clock()
end

@Simeon Here’s something I ran into playing with coroutines, which is a problem. Run the below code and the sprite will move slowly as it’s supposed to the way I have it coded. So that’s no problem. Stop the program and then comment out the coroutine.yield statement in function xx. Run the code and nothing happens because of the missing yield code. No problem. Stop the program to get back to the editor. Everything seems normal except you can’t run the code anymore. You can exit the editor, come back in and you still can’t run the code. You have to exit Codea before things work again. I think the coroutine is still running until you exit Codea which forces it to stop.

displayMode(FULLSCREEN)

function setup()
    fill(255)
    co=coroutine.create(xx)
    xv,yv=3,2
    zz=0
    x,y=WIDTH/2,HEIGHT/2
end

function draw()
    background(0)
    sprite(asset.builtin.Planet_Cute.Character_Princess_Girl,x,y)
    x=x+xv
    y=y+yv
    if x<0 or x>WIDTH then
        xv=-xv
    end
    if y<0 or y>HEIGHT then
        yv=-yv
    end
    text(zz,WIDTH/2,HEIGHT/2)
    coroutine.resume(co)
end

function xx()
    for a=1,100000000 do
        for b=1,10000 do
            c=math.sqrt(b)
        end
        zz=a
        if a%100==0 then
            coroutine.yield()  
        end 
    end
end

I use coroutines in Codea when I want to do something that typically runs much slower than a usual draw cycle. I have a program that draws Penrose tilings and when the number of tiles gets large then it takes too long to process all of them in one draw cycle, so I use coroutines to do a bit every draw.

Outside Codea, I’ve used coroutines to iterate through solutions to problems to find ones with specific properties.

@Jarc - @LoopSpace introduced me to coroutines when I introduced a puzzle thread and I needed to slow down sections. Lot of code in it, may help to look at - link below:

https://codea.io/talk/discussion/10107/and-now-for-something-completely-different/p1

@dave1707 very interesting bug! I’m really curious to see what the issue is. Will let you know

@Simeon - @dave1707 - ran this code and it’s a little more complicated. After commenting out the coroutine line in xx() and running, stopping and going back in you can not run the program anymore as stated - but if you come out of the editor and try other programs, I tried three others, none of them would run.

@Bri_G I never thought of trying other programs. But I guess that makes sense since nothing worked right until you got out of Codea itself. I wonder if I cut the run time of the function xx so that it would eventually end, if that would release the problem.

@Simeon The full run time of the function xx is about 12 hours. I changed the value of the first for loop so the run time was about 45 seconds. If you comment out the yield and run the code like above, when you press the run icon just once and wait, the program will eventually start after function xx runs it’s course. So the coroutine is blocking the second run.

#Simeon - is it possible to close coroutines in the stop routine. Do they register as part of the project or as separate routines in the system.

Edit: taking this further how would you cope with this in Xcode exports?

I looked into this and it’s not possible for me to stop them if you don’t yield

One way I can think to do this would be to write my own coroutine wrapper that gets used instead of Lua’s. Then keep track of all the internal Lua States created whenever coroutines are created. Then on shutdown progressively shut down any coroutines from the main thread. Seems fragile though

Another way might be to force-close any unfinished runtime instances the next time you attempt to run the viewer

It’s fairly complex as Lua and the native code run on separate threads, and shouldn’t ever really touch. But if Lua is stuck in an infinite loop we force an error on the Lua thread from the main thread — however with a coroutine we don’t even have a copy of the Lua state that was created off the Lua thread to force an error on

Thanks for finding it, even not being able to fix it, it’s an interesting problem

@Simeon - is it possible to build in a default yield() routine such that failure in the lua based coroutine falls to the safety net which generates an error and drops out of the lua program. Basically sandboxing coroutines.

Edit: other thought could you parse the program before running to check for integrity? You’ve probably got that but does it check coroutine integrity?

@Simeon Here’s another strange thing with the coroutine. Run the code below. Function xx will print xx started, the size of str multiple times, then xx ended. Everything is OK. Change the value of the b for loop from 2 to 3 and run the code again. The function xx doesn’t end. There’s a memory error that doesn’t show which is stopping the coroutine. If I call function xx not as a coroutine with the value of 3, I get a message not enough memory.

displayMode(STANDARD)

function setup()
    fill(255)
    str="qwerty"
    co=coroutine.create(xx)
    xv,yv=3,2
    zz=0
    x,y=WIDTH/2,HEIGHT/2
end

function draw()
    background(0)
    sprite(asset.builtin.Planet_Cute.Character_Princess_Girl,x,y)
    x=x+xv
    y=y+yv
    if x<0 or x>WIDTH then
        xv=-xv
    end
    if y<0 or y>HEIGHT then
        yv=-yv
    end
    text("a = "..zz,WIDTH/2,HEIGHT/2)
    coroutine.resume(co)
end

function xx()
    print("xx started")
    for a=1,10 do
        for b=1,2 do
            c=math.sqrt(b)
            str=str..str
            print("str size = "..#str)
        end
        zz=a
        if a%100==0 then
            --coroutine.yield()  
        end 
    end
    print("xx ended")
end