Howdy, Stranger!

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

Flickering screen but no drawing is occuring

edited July 2013 in Questions Posts: 90

I have a small program that does very little right now (most of it just dummy code), but it's been very aggravating and I don't know what's going on.

The program has several tabs (where each tab represents one "command"), implements one class per tab, and each tab has its own xyz:setup() and xyz:draw() methods. The Main tab's setup() fn has an array of one instance of each tab. When a command is executed, the instance corresponding to it is retrieved from the array and assigned to variable "currentCommand", and then currentCommand:setup() is run, which does the expected thing, plus sets a variable "done" to false. (This technique is used in a lot of the Codea examples.) currentCommand.draw() looks like:

function commandX:draw
if done then return
commandX:draw()
done = true
end

Assume CommandA is the first command that runs: it's supposed to clear the canvas and draw a word on the canvas. CommandB just clears the canvas. So if I haven't lost you by now, when the user runs a new command, the result should be that the canvas gets overdrawn once per command and that's all. (The ultimate goal is each command draws a boring graph, nothing animated.)

It can't get much simpler. Yet when commandA runs, it does create its image on the canvas, but then it flickers like it's getting redrawn. When commandB runs, it doesn't clear the screen, and A's output still flickers. Switching back and forth does nothing except that occasionally A's output freezes, but the next switch starts it flickering again.

So the question is: why is nothing getting cleared? Why is it flickering? I've tried various displayMode() and background() settings, it doesn't seem to matter. Surely the methods, although having the same names setup() and draw(), aren't getting automatically executed? I put a print statement in the draw() method, and it does look like it's getting executed only once (controlled by variable "done"), so what's causing the flickering? What am I'm overlooking or not understanding? Thanks.

Comments

  • BriarfoxBriarfox Mod
    Posts: 1,542

    do you have a background() in draw? If not is will not clear the screen.

  • Posts: 90

    Currently I have the call to displayMode() in function setup() (so it's done exactly once in the entire program), while each method cmd:draw() has the call to background(), where the function draw() calls the method. After calling the cmd:draw() method, the boolean flag "done" is set true, so the next time draw() is called it should immediately exit. That's the theory, anyway.

  • edited July 2013 Posts: 90

    (I meant "backingMode" in my previous message, not "displayMode".)

    I have since modified the system so that commandB draws a different message. When I run it and toggle between the two commands, sometimes I see messageA, messageB, or both, and they flicker, even though debug "print" statements show I only call the function draw() once per command (as expected). I tried it with backingMode(STANDARD), both before and after a background(0,0,0) call--no difference. If I stab at the button repeatedly I can make the messages appear singly or on top of each other randomly, and they always flicker.

    I notice that the ref docs say the backingMode(STANDARD) may remember what was drawn previously, and backingMode(RETAINED) will remember. Is there any way to say never remember what was drawn? (This won't address the flickering but it could stop the messages overlaying each other.)

  • edited July 2013 Posts: 391

    @starblue, not sure if this is the problem, but you may have an order of operations mistake. If you have an if statement like follows:

    if done then
        return something
        done = true
    end
    

    The line done = true will never be called since if done is true, it enters the if statement and the first thing it does is return something and ends the call before the next line.

  • Posts: 90

    OK, I have stripped the program down to its minimum. You should be able to load it into Codea and see for yourself. Start it. The first button "Collect" appears and draws "Metro Clock" in the context area. Click it, the second button "Stop Collecting" appears, taking the first button's place, and draws "Collecting". Press it and the cycle repeats.

    If you press the buttons fast enough, you'll see one message, the other, or one on top of the other, and they flicker as if they're being repeatedly drawn, even though each tab's draw() method is only called once. Codea's draw() function is called repeatedly by Codea, but the "done" flag is false only once per command, to call its tab's draw() method, and then set true so that later calls to the draw() function return immediately with no further calls to the tab's draw() method. (Be careful to distinguish Codea's draw() function vs. each tab's draw() method in my description.) Look at the code once, run it once, it should be obvious what it's (supposed to be) doing, and what it is doing.

    Any explanations? Any fixes?

    --# Intro
    Intro = class()
    
    function Intro:init()
        self.name = "intro"
    end
    
    function Intro:getName()
        return self.name
    end
    
    function Intro:setup()
        print "In Intro:setup"
        parameter.clear()
        parameter.action("Collect", function(dontcare) button_callback("collect") end)
    --    parameter.action("Save",    function(dontcare) button_callback("save") end)
    --    parameter.action("Load",    function(dontcare) button_callback("load") end)
    --    parameter.action("Plot",    function(dontcare) button_callback("plot") end)  
        done = false
    end
    
    function Intro:draw()
        backingMode(STANDARD)
        background(0, 0, 0)
        fontSize(100)
        fill(255,0,0)
        text(MainApp.title, WIDTH/2, HEIGHT/2)
        print(i)
        i = i + 1
    end
    
    function button_callback(n)
        current_action = actions[n]
        current_action:setup()
    end
    
    --# Collect
    
    Collect = class()
    
    function Collect:init()
        self.name = "collect"
        -- do nothing    
    end
    
    function Collect:getName()
        return self.name    
    end
    
    function Collect:setup() 
        print "In Collect:setup"    
        parameter.clear()
        parameter.action("Stop Collection", function(dontcare) self.exit() end)
        done = false
    end
    
    function Collect:draw()
        backingMode(STANDARD)
        background(0, 0, 0)
        fontSize(100)
        fill(255,0,0)
        text("Collecting", WIDTH/2, HEIGHT/2)
    end
    
    function Collect:exit()
        button_callback("intro")
    end
    
    --# Main
    MainApp = class()
    MainApp.title = "Metro Clock"
    
    -- Use this function to perform your initial setup
    function setup()
        print(MainApp.title)
    --    backingMode(STANDARD)
        i = 0
        actions = {intro   = Intro(), 
                   collect = Collect(), 
    --               save    = SaveLoad("save"), 
    --               load    = SaveLoad("load"), 
    --               plot    = Plot(),
                   }
        current_action = actions["intro"]     --Intro instance
        current_action:setup()
    end
    
    -- This function gets called once every frame
    function draw()
        if not done then 
            current_action:draw()
        end
        done = true
    end
    
  • edited July 2013 Posts: 391

    Try this out:

    --# Intro
    Intro = class()
    
    function Intro:init()
        self.name = "intro"
    end
    
    function Intro:getName()
        return self.name
    end
    
    function Intro:setup()
        print "In Intro:setup"
        parameter.clear()
        parameter.action("Collect", function(dontcare) button_callback("collect") end)
    --    parameter.action("Save",    function(dontcare) button_callback("save") end)
    --    parameter.action("Load",    function(dontcare) button_callback("load") end)
    --    parameter.action("Plot",    function(dontcare) button_callback("plot") end)  
        done = false
    end
    
    function Intro:draw()
        fontSize(100)
        fill(255,0,0)
        text(MainApp.title, WIDTH/2, HEIGHT/2)
        print(i)
        i = i + 1
    end
    
    function button_callback(n)
        current_action = actions[n]
        current_action:setup()
    end
    
    
    --# Collect
    
    Collect = class()
    
    function Collect:init()
        self.name = "collect"
        -- do nothing    
    end
    
    function Collect:getName()
        return self.name    
    end
    
    function Collect:setup() 
        print "In Collect:setup"    
        parameter.clear()
        parameter.action("Stop Collection", function(dontcare) self.exit() end)
        done = false
    end
    
    function Collect:draw()
        fontSize(100)
        fill(255,0,0)
        text("Collecting", WIDTH/2, HEIGHT/2)
    end
    
    function Collect:exit()
        button_callback("intro")
    end
    
    
    --# Main
    MainApp = class()
    MainApp.title = "Metro Clock"
    
    -- Use this function to perform your initial setup
    function setup()
        print(MainApp.title)
    --    backingMode(STANDARD)
        i = 0
        actions = {intro   = Intro(), 
                   collect = Collect(), 
    --               save    = SaveLoad("save"), 
    --               load    = SaveLoad("load"), 
    --               plot    = Plot(),
                   }
        current_action = actions["intro"]     --Intro instance
        current_action:setup()
        done = false
        backingMode(STANDARD)
    end
    
    -- This function gets called once every frame
    function draw()
        background(0, 0, 0)
        if not done then 
            current_action:draw()
        end
    end
    
  • Posts: 90

    Interesting. By removing "done=true" you made draw() execute every cycle, halting the flicker. It seems you can't draw just once because Codea isn't just calling draw() 60x/sec, it's modifying the screen that often. Why Codea would bother to do that I don't know.

    Using that insight, I revised the Main tab slightly and show it below. I kept to my original logic of calling method draw() only once per button press. However, it only works by setup() calling backingMode(RETAINED) so the screen contents don't get erased by Codea on its whim, which it seems STANDARD allows. The call to background() is placed accordingly.

    Thanks for your assistance.

    MainApp = class()
    MainApp.title = "Metro Clock"
    
    -- Use this function to perform your initial setup
    function setup()
        print(MainApp.title)
        i = 0
        actions = {intro   = Intro(), 
                   collect = Collect(), 
    --               save    = SaveLoad("save"), 
    --               load    = SaveLoad("load"), 
    --               plot    = Plot(),
                   }
        current_action = actions["intro"]     --Intro instance
        current_action:setup()
        backingMode(RETAINED)    --RETAINED needed for "done" boolean to work
    end
    
    -- This function gets called once every frame
    function draw()
        if not done then 
            background(0, 0, 0)    --inside "if" for "done" boolean to work
            current_action:draw()
        end
        done = true
    end
    
Sign In or Register to comment.