Code help

How can I get the script to wait 1 second before moving on with the rest of the script?
Like,
Do this
Wait 1 second
Continue with this

Use a simple timer like this one.

function setup()
    timer=ElapsedTime
    NumberOfSeconds=2
end

function draw()
    background()
    if ElapsedTime>timer+NumberOfSeconds then
        ellipse(WIDTH/2,HEIGHT/2,100)
    end
end

You can’t exactly wait, but you can skip over sections of code so it appears like you’re waiting. In this example, I’m waiting 1 second to add 1 to count. I’m always displaying the text, but skipping over the code to add 1 and executing it once every second.


function setup()
    et=ElapsedTime
    count=0
end

function draw()
    background(40, 40, 50)
    fill(255)
    if ElapsedTime-et>1 then
        count = count + 1
        et=ElapsedTime
    end   
    text(count,WIDTH/2,HEIGHT/2)
end

This is, hands down, the easiest way to effect a delay:


print("Hello!")

tween.delay(1, function()
    print("Hello again, after 1 second!")
end)

The best part is, it’s built into Codea.

Can we please stop recommending the old “put an accumulator in the draw function” chestnut whenever someone asks about how to delay execution of code (which seems to happen at least weekly)? The tween.delay solution is much more generic, reusable, practical, doesn’t require you to modify the draw function, doesn’t require using global variables, and takes a lot less code :slight_smile:

This is great. Bookmarked! Thanks.

tween.delay only works if it is something that doesn’t always occur. If you toss that tween.delay into the draw function without a test on an accumulator then it will delay the call, but since it will be constantly called every frame, it only delays the first second. If you need something to be called once every second, then using an accumulator is the only route to go.

For example: displaying frame rate on the screen and having it only update once every second. Something like this needs to be in the draw function since I want fps to be shown every frame, but I only want the number to change once every second.

function showFPS()
    if fpsStep < ElapsedTime then
        fpsStep = ElapsedTime + 1
        fps = math.floor(1/DeltaTime)
    end
    pushStyle()
    if fps >= 50 then
        fill(0, 255, 0, 255)
    else
        fill(255, 0, 0, 255)
    end
    rect(WIDTH - 80, 0, 80,20)
    fill(0, 0, 0, 255)
    text("FPS: "..fps, WIDTH - 38, 10)
    popStyle()
end

fpsStep is used to make sure the fps only updates once every second, otherwise the frame rate would change 60 times a second and would be mostly unreadable.

Tween.delay works, but you need a little more code. See below.


function setup()
    print("Hello!")
end

function draw()
    background(40, 40, 50)
    if a==nil then
        a=tween.delay(3,aaa)
    end
end

function aaa()
    print("Hello again after 3 seconds")
    a=nil    
end

@dave1707, nice, this is very good to know. Essentially, the tween.delay return value is acting as the accumulator. Still looks much cleaner than the standard timer. I like it.

@Slashin8r:

“If you toss that tween.delay into the draw function without a test on an accumulator then it will delay the call, but since it will be constantly called every frame, it only delays the first second”

Why would you use tween.delay in a draw call, or at least, what practical reason would there be for calling tween.delay every time draw() was called? I personally cannot think of any reason to ever do this. One of the benefits of tween.delay is that you don’t need to do anything in draw() (i.e., you can use tween.delay anywhere in your program, without having to modify draw() at all).

“If you need something to be called once every second, then using an accumulator is the only route to go”

Not true. Observe:


function repeatAfterInterval(interval, fn)
    tween.delay(interval, function()
        fn()
        repeatAfterInterval(interval, fn)
    end)
end

repeatAfterInterval(1, function()
    print("Hello!")
end

Again, nothing in the draw function, no globals needed (well, except the function repeatAfterInterval, but it only needs to be defined once and can be re-used throughout your program). I’ve left out the bit about cancelling a repeating interval call, but there are numerous (fairly) simple ways to handle that.

Now, I will concede that tween.delay will not work in every situation (such as calculating FPS). However, for generally delaying code execution, it is the most practical solution. @Mason asked for a way to “Do this Wait 1 second Continue with this”, and tween.delay is the easiest way to achieve exactly that.

I know I’ve already posted probably 3 different versions of generic timer code around the forums, but this post inspired me to flesh out the above repeating example more fully and come up with an implementation based on tween.delay. This code allows you to cancel a delayed call, pass arguments to your delayed call, and repeat your delayed call. Here are timeout(), timeout.loop(), and timeout.forever():

-- timeout
     
local function loop(interval, times, fn, ...)
    local rp, token
    local args = (select("#", ...) > 0) and {...} or nil 
        
    if times == 0 then
        if args then
            rp = function()
                return tween.delay(interval, function()
                    token.tween = rp()                
                    fn(unpack(args))
                end)
            end                
        else
            rp = function()
                return tween.delay(interval, function()
                    token.tween = rp()                
                    fn()
                end)
            end                            
        end
    else
        local count = 0
            
        if args then
            rp = function()
                return tween.delay(interval, function()                 
                    count = count + 1 
                    token.tween = (count < times) and rp() or nil
                    fn(unpack(args))                    
                end)
            end                
        else
            rp = function()
                return tween.delay(interval, function()                 
                    count = count + 1 
                    token.tween = (count < times) and rp() or nil
                    fn()                    
                end)
            end                                
        end
    end
        
    token = {
        tween = rp(),
        stop = function()
            if token.tween then
                tween.stop(token.tween)
                token.tween = nil
            end
        end
    }
        
    return token
end    

timeout = setmetatable({
    loop = loop,
    forever = function(interval, fn, ...) 
        return loop(interval, 0, fn, ...)
    end
}, {
    __call = function(self, ...)
        local token
            
        token = {
            tween = tween.delay(...),
            stop = function()
                if token.tween then
                    tween.stop(token.tween)
                    token.tween = nil
                end
            end
        }
            
        return token
    end
})

Here is a simple program to demonstrate it’s usage and features:


function setup()
    -- simple timeout, fires once after 1 second
    timeout(1, function()
        print("timeout complete")
    end)
    
    -- fires every second, 3 times
    timeout.loop(1, 3, function()
        print("You should see this 3 times")
    end)
    
    -- fires repeatedly, forever, every second
    local count = 0
    timeout.forever(1, function()
        count = count + 1
        print("forever count: " .. count)
    end)    
    
    -- you can cancel timeout(), timeout.loop(), and timeout.forever() by
    -- keeping the returned token object, and calling cancel on it.
    -- also, you can pass arguments to timeout() et al, and those will
    -- be forwarded to your callback (in this case, we're using the print
    -- function as our callback, and passing a string to it)
    local token = timeout.forever(1, print, "this will get called forever, until token.stop() is called")
    
    -- after 2 seconds, cancel the repeating timer
    timeout(2, function()
        token.stop()
    end)
end

“Why would you use tween.delay in a draw call, or at least, what practical reason would there be for calling tween.delay every time draw() was called?”

@toadkick, that’s exactly why I said tween.delay wouldn’t be the best route to accomplish what @Mason was asking. In order to utilize tween.delay, you have to know exactly what you will be delaying and it would have to be setup in advance.

I don’t think any of us actually provided a solution to his question. I believe what he is really asking is how do you pause everything. Tweens and timers only delay something from being called, it doesn’t actually pause a script at a designated line of code and prevent it from continuing to the next line.

For example, in Java you would use Thread.sleep(milliseconds) and the script would pause on that line for the given number of milliseconds.

Since the draw function is the heart of any program made with Codea and it automatically runs on its own every frame, how do you go about pausing it? Well, since you can’t stop the draw function, you have to stop the things inside it from being called, when you want to stop them and for how long you want to stop them. A series of timers is the best way to accomplish this. To have it “Do this Wait 1 second Continue with this” you would need to use if statements in conjunction with timers. We don’t ever want to pause the draw function as that would mean nothing will be drawn and animations would halt. So we need the draw function to skip certain events at certain times.

@toadkick, I can see how your suggestions may be useful for debugging and the logic behind them is sound, but when it comes to developing a game, not using the draw function is out of the question. If I were to setup all of my timers as tweens in my setup function, then all I would accomplish is a fast way for my game to crash as all of these looping tweens would be running at the same time my draw function is running. The draw function is named draw for a reason, so I would never use a tween.delay in the setup function to accomplish a drawing task. Like I said above, the draw function is the heart of any program in Codea as it beats 60 times a second. It would be redundant and unnecessary to add more hearts to your program.

@Slashin8r: I give up with you man. You are determined to undermine everything I say for some reason, and I am not going to argue with you. FWIW, I developed games professionally for 12 years, across many different platforms. I’ve used methods like the one I’ve described, with great success (stability-wise, performance-wise, readability-wise, as well as with ease of debugging) in every single one of them. So, think what you want, argue if you want; frankly, I don’t really care.

Also, FWIW, my typical draw function contains usually only about 10-20 lines of code, and I have always been able to pause my games without preventing the draw function from being called…

Well Thanks guys! I was unaware of using tween.delay. I re wrote my timer classes to use it.

@toadkick, I am just determined to help others and give out correct information. It’s not like I come on these forums to find you and argue with you, but it really seems like you enjoy doing that to me. My experience in developing games is just as broad as yours and with being here for over a year less than you I’ve probably accomplished more and given more to the community. Yes, I am still learning everything Codea has to offer, but I still know a lot of other programming languages and know to use functions for what they were made for. The tween.delay function was not created to pause a script, it was created to delay an animation. Also, you don’t think the tween.delay function utilizes a timer and tests this timer against ElapsedTime? How else would it know when its delay time is up? Why would I make my own timer instead of using a function that already does this? Well I would rather make my own timer because the tween function does beyond what I need the timer to do. Simple is always better when it comes to programming.

:smiley:

Can’t we all just get along :slight_smile:

It seems like this post turned into who can write the best delay. That wasn’t the purpose of the question that @Mason asked. He just wanted to know how to do THIS, wait 1 second, then continue with THIS. He didn’t specify exactly where THIS was at, so it could have been in draw(), or it could have been anywhere else. You can’t delay code, you can only not execute it for a given period of time, simulating a delay. How you do that determines where the delay is, your experience with coding, and how important your code is ( for fun or for sale). This is a TEACHING forum and the more answers/examples that are given, the better it is for the person who asked the question. There may be better ways to do something, but it’s still the choice of the reader as to what code he/she wants to use. FWIW, I developed code professionally for 38 years across different platforms, and one thing that I learned is, there isn’t only one way of doing something. It all comes down to, the best way is the way that works consistently with the best results.

@dave1707: I agree, there isn’t only one way of doing something. I wasn’t arguing that there was only one way. The thing about this specific issue is, this question gets asked very frequently, and every single time, the “use an accumulator in draw()” answer is presented as the first (and usually, the only) solution (a better forum search feature would really help here…). Hence the frustration in my initial post.

The thing is, it’s not a simple solution, especially if there’s more than one thing in your program that you need to “delay”. There are a lot of moving pieces to it. Sure, it can be helpful to know what’s actually going on under the hood, but is it actually simpler, or more helpful? I mean, I drive a car pretty much every day, and I have no idea how it works. I do know though that eschewing using it because I don’t know how it works would massively complicate my life.

EDIT: There was a bit here about not needing to know what the OP wanted to delay…I take that back, you do need to know at least some information for certain solutions. Mea culpa.

I’ll will admit that my responses that followed my initial answer weren’t entirely warranted; however, my next response was an answer to the notion that it was not possible to call deferred code repeatedly without an accumulator, and was not entirely off topic (even if it was a bit advanced). The one following that was perhaps completely unwarranted, and a little too advanced to have been posted without solicitation. Sorry, I got excited :slight_smile:

Also, I’ve been a human for 34 years now…and I’m sorry I dragged my experience into the discussion. I hate when other people do it, and I’m sorry I did it. It just kind of hurt having someone imply that I have no idea how games are made, and then proceed to tell me that my solution is actually not very useful.

@toadkick I agree that it seems like the same questions are asked over and over again, without searching previous discussions to see if that question was already asked. But I don’t think the forum search is very good and doesn’t go back far enough sometimes to do any good. I have an iPad 1, so the forum search doesn’t work for me anymore anyways. Also, the person asking the question might not know what to search for. As for your tween.delay(), I never thought about using it like that, so I even learned something from the original question. And that’s the point of this forum, to learn. Even though I have a lot of coding experience, there is still a lot I don’t know about Lua and Codea. That’s why I’m here, not to judge, but to help when I can and to learn when I can.

@dave1707: My apologies to you, seriously. The solution you provided was perfectly fine, and I didn’t mean to diminish it. I should have just left out the editorial in my first post, it was not helpful and did not provide any useful information, and it’s probably the reason this whole thing got started.

Also, not sure if this came across, but I think we are in agreement about the search feature. It is practically useless, and you can’t really admonish people for not using it when it doesn’t really work.

If it did work, you could see that I’ve actually provided code (in response to a similar question) to do what tween.delay does, long before tween.delay even existed :slight_smile:

Due to the frequency of this question, it might be nice to have a sticky post about timers/delaying code…not this one :stuck_out_tongue: , but one that does provide both of the basic solutions presented here.