Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Coroutines Help

edited May 1 in Questions Posts: 124

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

Comments

  • edited May 1 Posts: 124

    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
    
  • Posts: 489

    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.

  • Posts: 124

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

  • Posts: 124

    @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
    
  • Posts: 489

    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.

  • Posts: 1,726
    @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
  • dave1707dave1707 Mod
    Posts: 8,398

    @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
    
  • SimeonSimeon Admin Mod
    Posts: 5,364

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

  • Posts: 1,726

    @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.

  • dave1707dave1707 Mod
    Posts: 8,398

    @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.

  • dave1707dave1707 Mod
    Posts: 8,398

    @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.

  • edited May 4 Posts: 1,726
    #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?
  • SimeonSimeon Admin Mod
    Posts: 5,364

    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

  • edited May 4 Posts: 1,726
    @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?
  • dave1707dave1707 Mod
    Posts: 8,398

    @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
    
Sign In or Register to comment.