Friday, June 22, 2012

Interlude 1 - Delay / Sleep & Display Frame Rate (Updated 3/9/15)

Version Information


This tutorial has been updated for Codea version 2.3.1(47). You can check your version of Codea by tapping on the Two Lives Left logo in the bottom middle of the Codea start screen (Tutorial 1, Figure 1).


Interlude 1.1 Delay and Frame Rate


A question on the Codea Forums got me thinking about how you might slow things down if your code is animating too quickly. There is no sleep or delay function in Lua so initially I thought something like the following would work.

function delayForSeconds(secs)
    secs = secs or 1
    local endTime = os.time() + secs
    while os.time() < endTime do end
end

This doesn't actually work on my iPad unless you use a delay of greater than 65 seconds. Which is not particularly useful. Why is this so?

Well if you whip out your handy print() function and have a look at what os.time() returns you will see that it is a VERY large number (something like 1.34e+09 which is the number of seconds since the EPOCH or possibly something else...). A quick visit to the Codea Reference will tell you that the number you get backs depends on your system. There is probably something useful that you can do with this but Codea provides easier ways.

So next I looked at DeltaTime and ElapsedTime. Note that the trick with using these is they only change each time draw() gets called so you can't use them in separate function and wait for these to change to the value you are looking for.

The approach I ended up with is shown in the code example below which prints out the frame rate every second. Remember in Tutorial 1 I said that Codea tries to call the draw() function 60 times per second, this code will show you what is actually being achieved. if you have a complex program your frame rate may be less than 60.

function setup()
    initTimeValue = ElapsedTime
    frameCounter = 0
end

function draw()
    if (ElapsedTime - initTimeValue < 1) then
        frameCounter = frameCounter + 1
    else
        print("Frames per second: "..frameCounter)
        frameCounter = 0
        initTimeValue = ElapsedTime
    end
end


Interlude 1.2 A Better Approach to Displaying Frame Rate


The problem with the previous approach to displaying frame rate for your program is that it is continually printing to the console. This makes it difficult if you are printing out other variables or status because they keep scrolling off the screen.

A better approach is to use the parameter.watch() function which is designed specifically for monitoring variables in real time. Here is the revised code.

function setup()

    -- FPS is the variable which contains our Frames Per Second calculation

    FPS = 0
    parameter.watch("FPS")

    timeInterval = 0
    frameCount = 0

end

function draw()

    -- Set the background to Black

    background(0, 0, 0)

    -- Calculate Frames Per Second (FPS)

    frameCount = frameCount + 1
    timeInterval = timeInterval + DeltaTime

    if timeInterval > 1 then
        FPS = math.round(frameCount / timeInterval)
        timeInterval = 0
        frameCount = 0
    end

end

function math.round(num)

-- There is no math.round in Codea currently.
-- Thanks to @Vega for providing this function

    return math.floor(num + 0.5)

end

Interlude 1.3 An Even Simpler Approach to FPS


function setup()


-- FPS is the variable which contains our Frames Per Second calculation

    FPS = 0
    parameter.watch("FPS")

end

function draw()


    -- Set the background to Black

    background(0, 0, 0)

    -- Calculate Frames Per Second (FPS)
    --
    -- DeltaTime = time in seconds since the last frame was drawn,
    -- it is a number provided by Codea.


    FPS = math.round(1/DeltaTime)

end

function math.round(num)

-- There is no math.round in Codea currently.
-- Thanks to @Vega for providing this function

    return math.floor(num + 0.5)

end

If we add this to our rounded rectangle app from Tutorial 2 it will look like Figure 15.


Figure 15. RoundRect with FPS.

When we run the updated program, you will be able to see (Figure 16) that drawing a rounded rectangle runs at 60 frames per second or thereabouts as we would expect - since it isn't a very complicated rendering exercise. You will need to scroll down to see the FPS parameter as it was the last one that we added.


Figure 16. FPS Displayed

4 comments:

  1. Dear David,

    I'm following your tutorial. Very nice...
    One little mistake here:

    -- FPS is the variable which contains our Frames Per Second calculation
    FPS = 0
    watch(FPS)

    Should be:

    -- FPS is the variable which contains our Frames Per Second calculation
    FPS = 0
    watch("FPS")

    Franz

    ReplyDelete
  2. Hi Franz,

    Thanks for the comment and and well spotted. You are correct, this is one of the dangers of typing code in rather than copy and paste. I will correct it in the Tutorial.

    Cheers,

    D

    ReplyDelete
  3. Did you try using LUA's os.clock() function?
    It delivers time values in millisecs and can be used for small delays. I haven't tried it with Codea on iPad, but it works with LoveCodea on a Win machine.

    example for a milliseconds delay:

    function delay(msec)
    if msec>0 then
    local start=os.clock()
    local stop=start+msec/1000
    while os.clock()<stop do end
    end
    end

    ...quite wasteful on CPU time but works.

    ReplyDelete
    Replies
    1. Thanks for the code - yes that would probably work. As you say, there are more elegant approaches than just causing the CPU to spin its wheels.

      Delete