Displaying Timer on Screen

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
Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Displaying Timer on Screen

#1 Post by Fatimah »

Hello,

I'm trying to display a timer on screen, which I managed thanks to a code snippet I found here.
This is the timer.

init:
python:

# This function will run a countdown of the given length. It will
# be white until 5 seconds are left, and then red until 0 seconds are
# left, and then will blink 0.0 when time is up.
def countdown(st, at, length=0.0):

remaining = length - st

if remaining > 2.0:
return Text("%.1f" % remaining, color="#fff", size=72), .1
elif remaining > 0.0:
return Text("%.1f" % remaining, color="#f00", size=72), .1
else:
return anim.Blink(Text("0.0", color="#f00", size=72)), None


image countdown = DynamicDisplayable(countdown, length=120.0)

show countdown at Position(xalign=.1, yalign=.1)

It works but I'm not sure if it works in real time or not.
Also, for now, it displays the time like this:

60.0

where I want it to be like this:

60:00

and I want it to display the two minutes like:

2:00:00

not like: 160.0

Thank you for the help.

Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Re: Displaying Timer on Screen

#2 Post by Fatimah »

I managed to get the code to work as I need.
However, I've run in another problem,

Code: Select all

show countdown at Position(xalign=.1, yalign=.1)
        call screen geneticCodeLab
I'm showing the timer and then calling another screen which causes the timer to disappear.

Is there a way to always make on top?
I've tried the zorder but got an error

Thanks

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Displaying Timer on Screen

#3 Post by kivik »

Glad to hear you got it working! May be worth posting your end code for others who need it (I'd be curious myself!)

What was the error you got when you tried zorder? Always useful to share the error messages.

Regardless, the screen layer comes above the master layer: https://www.renpy.org/doc/html/displayi ... html#layer

So even if you manage to change the zorder, it won't ever go above the current layer (zorder is relative to other displayables on same layer) anyway, so you need to use the onlayer property: https://www.renpy.org/doc/html/displayi ... -statement

Alternatively make the countdown another screen, and give the screen a high zorder then you don't have to worry about the zorder or layer each time you show it.

Code: Select all

screen countdown:
    zorder 99

Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Re: Displaying Timer on Screen

#4 Post by Fatimah »

kivik wrote: Tue May 15, 2018 8:57 am Glad to hear you got it working! May be worth posting your end code for others who need it (I'd be curious myself!)

What was the error you got when you tried zorder? Always useful to share the error messages.

Regardless, the screen layer comes above the master layer: https://www.renpy.org/doc/html/displayi ... html#layer

So even if you manage to change the zorder, it won't ever go above the current layer (zorder is relative to other displayables on same layer) anyway, so you need to use the onlayer property: https://www.renpy.org/doc/html/displayi ... -statement

Alternatively make the countdown another screen, and give the screen a high zorder then you don't have to worry about the zorder or layer each time you show it.

Code: Select all

screen countdown:
    zorder 99
Sure :)

This is the timer:

Code: Select all

init:
    python:

        # This function will run a countdown of the given length. It will
        # be white until 5 seconds are left, and then red until 0 seconds are
        # left, and then will blink 0.0 when time is up.
        def countdown(st, at, length=0.0):

            remaining = length - st
            minutes = (int) (length - st) / 60
            seconds = (int) (length - st) % 60


            if remaining > 2.0:
                return Text("%02d:" % minutes + "%02d" % seconds, color="#fff", size=48), .1
            elif remaining > 0.0:
                return Text("%02d:" % minutes + "%02d" % seconds, color="#f00", size=48), .1
            else:
                return anim.Blink(Text("00:00", color="#f00", size=48)), None
I would put in a screen, but can you put a function on a screen?
Also, this timer would have different periods based on the choices the player made before this point and so I would like to be able to make it dynamic
so when I define the timer:

Code: Select all

image countdown = DynamicDisplayable(countdown, length=120.0)
the length would be different for each path of the story & I don't know if this would be possible if I put that in a screen.

kivik
Miko-Class Veteran
Posts: 786
Joined: Fri Jun 24, 2016 5:58 pm
Contact:

Re: Displaying Timer on Screen

#5 Post by kivik »

Oh cool, this is the exact code someone was looking for the other day. Unless it was you? XD

Anyway this works for me:

Code: Select all

screen countdown(cd_time):
    zorder 99
    frame:
        xalign 0.1
        yalign 0.1
        add DynamicDisplayable(countdown, length=cd_time)

label start:
    show screen countdown(120)
Basically here you're creating a fresh DynamicDisplayable each time you show the screen, instead of predefining the countdown as an image on init, so you can dynamically set the timer at whatever length you want in your game.

In fact I couldn't add the countdown image into the screen directly, it says it's not been defined, this is what confuses me about Renpy images!

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: Displaying Timer on Screen

#6 Post by Remix »

Within a screen you could pass in any parameter you need to change...

This code allows changing of pretty much all the parameters you might need

Code: Select all


style text_timer_ok:
    size 72
    color "#FFF"
    outlines [(2, "#000", 0, 0)]

style text_timer_near:
    size 72
    color "#F22"
    outlines [(2, "#000", 0, 0)]

init python:

    def text_countdown( st, at, 
                        duration = 10.0, 
                        fail_label = 'fail_label', 
                        screen = 'text_timer',
                        ok_style = 'text_timer_ok',
                        near_style = 'text_timer_near',
                        style_swap = 5.0,
                        text_format = "{minutes:02d}:{seconds:02d}:{micro_seconds[0]}" ):
        
        remaining = duration - st

        parts_dict = {
            'minutes' : int( remaining // 60 ),
            'seconds' : int( remaining % 60 ),
            'micro_seconds' : str(int( (remaining % 1) * 10000 )), # we use str() so we can define precision
        }

        if remaining <= 0.0:
            renpy.hide_screen(screen)
            renpy.call(fail_label)
        
        return Text( text_format.format(**parts_dict), 
                     style = ok_style if remaining > style_swap else near_style), .1

    

screen text_timer( **kwargs ):
    # @param: kwargs
    #
    # duration = 10.0, 
    # success_label = 'success_label',
    # fail_label = 'fail_label', 
    # screen = 'text_timer',
    # ok_style = 'text_timer_ok',
    # near_style = 'text_timer_near',
    # style_swap = 5.0,
    # text_format = "{minutes:02d}:{seconds:02d}:{micro_seconds[0]}"

    vbox:
        add DynamicDisplayable(text_countdown, **kwargs)

        #
        #
        # This would likely be in a different screen
        # Remember to alter the kwargs and move success_label there though
        #
        #
        textbutton "Found Me":
            action [ Function(renpy.hide_screen, 'text_timer'), Call(kwargs.get('success_label', 'success_label')) ]


label start:
    "start"
    call screen text_timer
    "middle"
    # with parameters (no micro_seconds, 22 seconds long)
    call screen text_timer(duration=22.0, text_format = "{minutes:02d}:{seconds:02d}" )
    "end"

label success_label:
    "Success"
    return

label fail_label:
    "Too slow"
    return
Note: I used Call rather than Jump for the events so we can use 'return' to go back to where we were in the script
Frameworks & Scriptlets:

Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Re: Displaying Timer on Screen

#7 Post by Fatimah »

kivik wrote: Thu May 17, 2018 4:15 am Oh cool, this is the exact code someone was looking for the other day. Unless it was you? XD

Anyway this works for me:

Code: Select all

screen countdown(cd_time):
    zorder 99
    frame:
        xalign 0.1
        yalign 0.1
        add DynamicDisplayable(countdown, length=cd_time)

label start:
    show screen countdown(120)
Basically here you're creating a fresh DynamicDisplayable each time you show the screen, instead of predefining the countdown as an image on init, so you can dynamically set the timer at whatever length you want in your game.

In fact I couldn't add the countdown image into the screen directly, it says it's not been defined, this is what confuses me about Renpy images!
Thank you so much for the help!
Yeah, I did try putting the image directly and couldn't.
Remix wrote: Thu May 17, 2018 5:23 am Within a screen you could pass in any parameter you need to change...

This code allows changing of pretty much all the parameters you might need

Code: Select all


style text_timer_ok:
    size 72
    color "#FFF"
    outlines [(2, "#000", 0, 0)]

style text_timer_near:
    size 72
    color "#F22"
    outlines [(2, "#000", 0, 0)]

init python:

    def text_countdown( st, at, 
                        duration = 10.0, 
                        fail_label = 'fail_label', 
                        screen = 'text_timer',
                        ok_style = 'text_timer_ok',
                        near_style = 'text_timer_near',
                        style_swap = 5.0,
                        text_format = "{minutes:02d}:{seconds:02d}:{micro_seconds[0]}" ):
        
        remaining = duration - st

        parts_dict = {
            'minutes' : int( remaining // 60 ),
            'seconds' : int( remaining % 60 ),
            'micro_seconds' : str(int( (remaining % 1) * 10000 )), # we use str() so we can define precision
        }

        if remaining <= 0.0:
            renpy.hide_screen(screen)
            renpy.call(fail_label)
        
        return Text( text_format.format(**parts_dict), 
                     style = ok_style if remaining > style_swap else near_style), .1

    

screen text_timer( **kwargs ):
    # @param: kwargs
    #
    # duration = 10.0, 
    # success_label = 'success_label',
    # fail_label = 'fail_label', 
    # screen = 'text_timer',
    # ok_style = 'text_timer_ok',
    # near_style = 'text_timer_near',
    # style_swap = 5.0,
    # text_format = "{minutes:02d}:{seconds:02d}:{micro_seconds[0]}"

    vbox:
        add DynamicDisplayable(text_countdown, **kwargs)

        #
        #
        # This would likely be in a different screen
        # Remember to alter the kwargs and move success_label there though
        #
        #
        textbutton "Found Me":
            action [ Function(renpy.hide_screen, 'text_timer'), Call(kwargs.get('success_label', 'success_label')) ]


label start:
    "start"
    call screen text_timer
    "middle"
    # with parameters (no micro_seconds, 22 seconds long)
    call screen text_timer(duration=22.0, text_format = "{minutes:02d}:{seconds:02d}" )
    "end"

label success_label:
    "Success"
    return

label fail_label:
    "Too slow"
    return
Note: I used Call rather than Jump for the events so we can use 'return' to go back to where we were in the script
Thank you so much!!
This code will definitely help me!

Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Re: Displaying Timer on Screen

#8 Post by Fatimah »

So this is my final code for the timer

Code: Select all

init:
    python:

        # This function will run a countdown of the given length. It will
        # be white until 5 seconds are left, and then red until 0 seconds are
        # left, and then will blink 0.0 when time is up.
        def countdown(st, at, length=0.0):

            remaining = length - st
            minutes = (int) (length - st) / 60
            seconds = (int) (length - st) % 60


            if remaining > 10.0:
                return Text("%02d:" % minutes + "%02d" % seconds, color="#fff", size=48), .1
            elif remaining > 0.0:
                return Text("%02d:" % minutes + "%02d" % seconds, color="#f00", size=48), .1
            else:
                renpy.jump("police_storming")
                #return anim.Blink(Text("00:00", color="#f00", size=48)), None

Code: Select all

screen countdown(cd_time):
    zorder 2
    frame:
        #xalign 1.0
        xpos 1250
        yalign 0.1
        background None
        add DynamicDisplayable(countdown, length=cd_time)
I'm calling the screen later in the code. However, the game freezes completely when the timer reaches 0:0 & I have no idea why is that.
There's no error message or anything. It just freezes.

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: Displaying Timer on Screen

#9 Post by Remix »

You need a hide to effectively remove the dynamic displayable, otherwise it would expect an (image, delay) return from the function

Code: Select all

            else:
                renpy.hide_screen("countdown")
                renpy.jump("police_storming")
Frameworks & Scriptlets:

Fatimah
Regular
Posts: 94
Joined: Tue Mar 01, 2016 2:53 pm
Contact:

Re: Displaying Timer on Screen

#10 Post by Fatimah »

Remix wrote: Mon May 21, 2018 7:14 am You need a hide to effectively remove the dynamic displayable, otherwise it would expect an (image, delay) return from the function

Code: Select all

            else:
                renpy.hide_screen("countdown")
                renpy.jump("police_storming")
Oh..I didn't know that.
Thank you so much for the help!

Post Reply

Who is online

Users browsing this forum: Ocelot, Semrush [Bot]