[solved] Timer action makes UDD flicker

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

[solved] Timer action makes UDD flicker

#1 Post by Milkymalk »

I'm totally stumped. I have this UDD that displays a small image following the mouse pointer. This worked fine and without problems:

Code: Select all

    class MouseItem(renpy.Displayable):
        def __init__(self, id):
            super(MouseItem, self).__init__()
            
            self.child = Image("images/items/"+id+"_i.png")
            mp = renpy.get_mouse_pos()
            self.pos = mp

        def render(self, width, height, st, at):
            render = renpy.Render(config.screen_width, config.screen_height)
            
            child_render = renpy.render(self.child, width, height, st, at)

            x,y = self.pos
            render.blit(child_render, (x-25, y-25))
            if showcursorfollow and x>=-800 and y>=-800:
                return render
            else:
                return renpy.Render(0,0)

        def event(self, ev, x, y, st):
            # Re-render if the position changed.
            if self.pos != (x, y):
                renpy.redraw(self, 0)

            # Update stored position
            self.pos = (x, y)
Then I added a timer to the game that is repeatedly executed and calls a function periodically. When I did this, the image began flickering in the rhythm of the timer:

Code: Select all

init python:
    def execute_gametick():
        for p in party:
            p.tick()
    
    class Blah(object): # party is composed of these
    #...
    
        def tick(self):
            ## tick temp effects
            for i in self.tempeffects:
                if i.ticking:
                    i.time -= 1
                    i.ticktime -= 1
                    if i.time == 0:
                        i.remove = True
                    if i.ticktime == 0:
                        apply_stats(self, i.stats)
                        i.ticktime = i.ticklength
                        # if i.tickmessage:
                        #     showmessage(i.tickmessage)
            for i in self.tempeffects:
                if i.remove:
                    self.tempeffects.remove(i)

screen waitforevent():
    timer ticklength repeat True action Function(execute_gametick)
Why is the UDD flickering when nothing the timer does is related to it, and how can I make it stop? This even persists if I comment out everything in execute_gametick, so p.tick isn't called at all. Replacing the action with NullAction() however stops the flickering.

What I understand from this is that the action Function() respectively the called function make the UDD flicker.
Last edited by Milkymalk on Sun May 27, 2018 9:40 am, edited 2 times in total.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: UDD flickers with timer

#2 Post by Remix »

Drop the timer screen totally (it basically redraws everything each tick)

Code: Select all

init python:
    renpy.config.periodic_callbacks.append( execute_gametick )
Roughly 20Hz which should be plenty for most use cases
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: Timer action makes UDD flicker

#3 Post by Milkymalk »

I actually need to redraw everything (or at the very least, a few screens) each tick as the game changes stuff in real-time. The callback is a great idea (again, I learned something useful exists), but skips this important step.
Curiously, even if everything is redrawn, only the one UDD flickers. Maybe it has to do with the way the UDD is programmed? I pretty much copied the flashlight code from another forum post and adapted it to my needs. I barely understand what it exactly does.
Also, edits in the text after the last code block which you maybe didn't see before writing your reply.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: Timer action makes UDD flicker

#4 Post by Remix »

On an aside:

Rather than systematically decreasing tempeffects.ticktime by 1 you'd likely do better setting actual values:

tempeffect.expires_at = renpy.display.core.get_time() + 25.0
...
if renpy.display.core.get_time() > tempeffect.expires_at: # remove effect

Then it doesn't matter if the 20Hz drops to 19 or jumps to 25 or whatever

For screens that need/want constant updating, I advise:

Code: Select all

init python:
    config.per_frame_screens.append( "my_animated_screen" )
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: Timer action makes UDD flicker

#5 Post by Milkymalk »

Thank you for the suggestion, as always :) It's just that this would interfere with game pauses, as the core time would keep passing while the game is on pause. But it's good to know this exists.

I will try the screen updating after I get some sleep, thank you. This sounds like the solution to my problem.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: Timer action makes UDD flicker

#6 Post by Milkymalk »

I applied a mix of your and my methods and it worked.

At first I used this:

Code: Select all

init python:
    renpy.config.periodic_callbacks.append( execute_gametick )
    config.per_frame_screens.append( "my_animated_screen" )
But it made the refresh rate jerky (about 4 refreshs per second, a test bar jumped instead of decreasing evenly) unless I kept producing events by using the mouse (this made it even). I think I just discovered part of Ren'Py's inner workings :D
Then I ditched the per_frame_screens.append for this:

Code: Select all

    renpy.config.periodic_callbacks.append( renpy.restart_interaction )
renpy.restart_interaction didn't make any difference in my first try with the timer, but then I remembered that the UDD is displayed at the bottom of a quite complicated screen. So I tried and moved it to its own screen and voilà, it works, the UDD doesn't flicker and the refresh rate is nice.

So, thank you, you definitely helped me realize what was wrong and I learned a little about using callbacks.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: [probably solved] Timer action makes UDD flicker

#7 Post by Remix »

Though I have not tested, I would advise against using renpy.restart_interaction inside the periodic callback. It will generally force Ren'Py to never take a breather during the entire game. Ren'Py naturally uses those breathers to do cleanup, caching or some lookahead prediction...

Instead, you could:
a) add a redraw my displayable call to the periodic which would then mean running a test to see if the displayable was there
b) recode the displayable as a dynamic (which could then naturally call a redraw on itself)
c) call a redraw at the end of the render method of the displayable ... renpy.display.render.redraw(self, 0.01) just before if showcursorfollow and x>=-800 and y>=-800:

I don't really have a simple use-case script to test any of those in though, so they are just open options
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: [probably solved] Timer action makes UDD flicker

#8 Post by Milkymalk »

Good point. Though the main reason for the renpy.restart_interaction is that without it, the screens don't refresh often enough. I tried renpy.force_complete_redraw, but this did absolutely nothing (probably doesn't re-render screens). The displayable itself isn't the problem anymore.

I would need to find a way to actually render a screen at a constant framerate (config.per_frame_screens only renders every 0.25 seconds or so while there are no mouse events, and every 0.05 seconds while the mouse is moving).

What I could do is settle for less frequent renpy.restart_interaction, using the timer I first employed. Now that the UDD is in its own screen, it doesn't flicker anymore. So instead every 0.05 seconds, it only restarts every 0.1 seconds. Or, by using the timer, I could still go for the full 20 restarts per second because the game will frequently go into a state where the game is "frozen" and standard visual novel stuff is going on, with no restarts.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: [probably solved] Timer action makes UDD flicker

#9 Post by Remix »

Milkymalk wrote: Sun May 27, 2018 8:47 ambecause the game will frequently go into a state where the game is "frozen" and standard visual novel stuff is going on, with no restarts.
Yup, during those is when you do not really want the restart_interaction going on... so maybe:

Code: Select all

init python:

    def keep_ticking():
        if renpy.get_screen( "tag_or_screen_name_with_my_displayable_in_it" ):
            renpy.restart_interaction()
            
    renpy.config.periodic_callbacks.append( keep_ticking )
... or just add the get_screen conditional to your other periodic function
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: [probably solved] Timer action makes UDD flicker

#10 Post by Milkymalk »

All right, then that's what I will do :) Thanks a lot for your help!
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

User avatar
Remix
Eileen-Class Veteran
Posts: 1628
Joined: Tue May 30, 2017 6:10 am
Completed: None... yet (as I'm still looking for an artist)
Projects: An un-named anime based trainer game
Contact:

Re: [solved] Timer action makes UDD flicker

#11 Post by Remix »

No prob.

Just for extra *learning* info:

renpy.get_screen( name [, layer] )

Returns the ScreenDisplayable with the given `name` on optional layer. ( if `name` is a list it returns first showing )
`name` is first interpreted as a tag name, and then a screen name.
If the screen is not showing, returns None. ## <-- so we use it in our conditional to only run the restart_interaction while it is shown
Frameworks & Scriptlets:

User avatar
Milkymalk
Miko-Class Veteran
Posts: 753
Joined: Wed Nov 23, 2011 5:30 pm
Completed: Don't Look (AGS game)
Projects: KANPEKI! ★Perfect Play★
Organization: Crappy White Wings
Location: Germany
Contact:

Re: [solved] Timer action makes UDD flicker

#12 Post by Milkymalk »

Yes, I found that one in the documentation after it was mentioned in another thread where I asked something. But thank you :)

I am actually experiencing a certain slowdown in the ticking when a lot of images are loading for the screens, but that's okay. This only happens when the player makes a lot of input in a very short time, in which case he either really needs the "bullet time" because there is a lot of dangerous stuff going on, or it doesn't matter because nothing important is happening and he is just rushing through the level.
If it becomes unbearable I can still turn the tickrate down to 10 ticks/sec.
Crappy White Wings (currently quite inactive)
Working on: KANPEKI!
(On Hold: New Eden, Imperial Sea, Pure Light)

Post Reply

Who is online

Users browsing this forum: No registered users