Variables in Screens

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
m_from_space
Regular
Posts: 26
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Variables in Screens

#1 Post by m_from_space » Sun Feb 21, 2021 4:11 am

Hey Forum,

I'm new here, but developing a project for a while now, and also enjoying the mostly well written documentation of Renpy.

But there is something I cannot really get my head around, and I didn't find sufficient information about it. Also I encountered strange behavior in one of my screens just by changing variable assignment.

Maybe you can answer some questions for me or give me hints.

Let's say we are inside some simple gameover screen and I know it can be more efficient, but it's about what's going on.

Code: Select all

default count = 0
default reason = 0
screen gameover():
    vbox:
        if reason == 0:
            $ count += 1
            text "You died, sorry."
        elif reason == 1:
            $ store.count += 1
            text "You drowned."
        showif reason == 2:
            timer 0.1 action SetVariable("count", count+1)
            text "You were shot."
        elif reason == 3:
            $ count += 1
            text "You had a heart attack."
        if reason == 4:
            $ store.count += 1
            text "You burned to death."
        elif reason > 4:
            timer 0.1 action SetScreenVariable("count", count+1)
            text "I don't know how you died."

        text "You died [count] times already."

        if count > 3:
            text "You died quiet often, you idiot."

        null height 50
        textbutton "Recover" action Return()
        textbutton "Die a random death" action SetVariable("reason", renpy.random.randint(0,10))

label start:

    $ reason = 1
    "*drinkswater*"
    call screen gameover
    $ reason = 2
    "*pewpew*"
    call screen gameover
    $ reason = 3
    "*sugarintake*"
    call screen gameover

    return
I know that python code within a "showif" statement is executed, even when the condition is false.

1. What's the difference writing count += 1 and store.count += 1 -- it seems that store.count will get executed even when the reason is not 1. Or at least the screen is forced to update?
2. What's a screen variable? I guess a local variable that was not assigned outside of the screen? How would I even initialize it? Wouldn't it be reset every time the screen is loaded/checked (which according to the documentation can happen at random times, as Renpy needs it. Why would I need a screen variable?
3. What does predicting a screen really mean? In my project I create very non-static screens that have a lot of conditions inside of them, and sometimes things don't work as intended and don't make sense to me.

I probably have more questions, but that's it for now. Thank you!

User avatar
Alex
Lemma-Class Veteran
Posts: 2727
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Variables in Screens

#2 Post by Alex » Sun Feb 21, 2021 6:47 am

m_from_space wrote:
Sun Feb 21, 2021 4:11 am
...

Code: Select all

screen gameover():
    vbox:
        if reason == 0:
            $ count += 1
You shouldn't put that logic into screens. Screens are reshown several times for internal purposes, so this part of code will be run several times (since 'reason' is not changed 'count' will grow).

Looks like you need to increase 'count' only once when 'gameover' screen is shown - try to make an 'on "show"' action

Code: Select all

screen gameover():
    on "show" action SetVariable("count", count+1)
You can keep if/elif/else for showing some text.

1. Psst.., actually, all your variables are fields of a 'store' object of Ren'Py. So, you can work with your variables like

Code: Select all

$ count += 1
or, if needed, set them as a field of object

Code: Select all

$ store.count += 1
(this might be useful in custom functions).

2. Screen variable is a variable that is used only inside the screen where it was defined. To set screen variable use 'default' statement inside a screen. This (default) value will be used every time you hide and show your screen again.

Code: Select all

screen test():
    default screen_var = 0
    textbutton 'ClickMe! ([screen_var])' action SetScreenVariable('screen_var', screen_var + 1) align (0.5, 0.05) text_size 55

m_from_space
Regular
Posts: 26
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Variables in Screens

#3 Post by m_from_space » Sun Feb 21, 2021 10:35 am

Alex wrote:
Sun Feb 21, 2021 6:47 am
m_from_space wrote:
Sun Feb 21, 2021 4:11 am
...

Code: Select all

screen gameover():
    vbox:
        if reason == 0:
            $ count += 1
You shouldn't put that logic into screens. Screens are reshown several times for internal purposes, so this part of code will be run several times (since 'reason' is not changed 'count' will grow).
Well, I disagree on "You shouldn't put that logic into screens.", and the above screen is just for demonstration purposes though. I don't mind if it is rerun serveral times, today's processors don't mind that at all. You're not right though, count will not just grow every time, but under several conditions, for example if part of a showif statement. But that isn't part of the documentation unfortunately.

Your hints of course are valid regarding using "on show".
Alex wrote:
Sun Feb 21, 2021 6:47 am
1. Psst.., actually, all your variables are fields of a 'store' object of Ren'Py. So, you can work with your variables like

Code: Select all

$ count += 1
or, if needed, set them as a field of object

Code: Select all

$ store.count += 1
(this might be useful in custom functions).
I know it's part of the store module. But something is different when changing the value inside of a screen and I don't really know why and what exactly is happening.

Thanks for the explanation for screen variables, I assumed that since the screen is rerun that a define/default statement would also be rerun.

Why can I set "count" with SetScreenVariable even though I didn't declare it within the screen?

User avatar
Alex
Lemma-Class Veteran
Posts: 2727
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Variables in Screens

#4 Post by Alex » Sun Feb 21, 2021 11:23 am

m_from_space wrote:
Sun Feb 21, 2021 10:35 am
... I don't mind if it is rerun serveral times, today's processors don't mind that at all. You're not right though, count will not just grow every time, but under several conditions, for example if part of a showif statement. But that isn't part of the documentation unfortunately.
...
I know it's part of the store module. But something is different when changing the value inside of a screen and I don't really know why and what exactly is happening. ...

https://www.renpy.org/doc/html/screens.html
Screens must not cause side effects that are visible from outside the screen. Ren'Py will run a screen multiple times, as it deems necessary. It runs a screen as part of the image prediction process, before the screen is first shown. As a result, if running a screen has side effects, those side effects may occur at unpredictable times.

User avatar
zmook
Regular
Posts: 170
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Variables in Screens

#5 Post by zmook » Sun Feb 21, 2021 12:52 pm

m_from_space wrote:
Sun Feb 21, 2021 4:11 am
2. What's a screen variable? I guess a local variable that was not assigned outside of the screen? How would I even initialize it? Wouldn't it be reset every time the screen is loaded/checked (which according to the documentation can happen at random times, as Renpy needs it. Why would I need a screen variable?
I'm still grappling with some of these details myself.
* Python variables don't have to be declared. If you just write `$ newvar = 10` it's allocated and initialized on the spot.
* `define newvar = 10` is equivalent to

Code: Select all

init python:
    newvar = 10
I *think* this is true even if the `define` is located within another block, like a screen statement. It's pulled out and executed at init time. It's useful for setting values that you intend to treat as constants.

* 'default newvar = 10` is equivalent to:

Code: Select all

label start:
	if not hasattr(store, 'newvar'):
	    newvar = 10
label after_load:
	if not hasattr(store, 'newvar'):
	    newvar = 10
So defaults are run after all defines and init blocks, and are only run once (if the variable does not exist). It should never reset a variable that already has a value. It's useful particularly for avoiding errors when you load an old save into a new game.
3. What does predicting a screen really mean? In my project I create very non-static screens that have a lot of conditions inside of them, and sometimes things don't work as intended and don't make sense to me.
I believe at a minimum it means getting a list of all the images that will be used on the screen so they can be rendered ahead of time. I would be curious to know what else happens, too.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

m_from_space
Regular
Posts: 26
Joined: Sun Feb 21, 2021 3:36 am
Contact:

Re: Variables in Screens

#6 Post by m_from_space » Sun Feb 21, 2021 4:18 pm

@alex I read this multiple times already, I know that, thanks for pointing out. What I meant was that the screen isn't just randomly redrawn, you can check this with my code example above. But sure, it's not predictable either. My code example was not for showing good programming skills, but how strange variable assignment acts in screens, with different methods. What "Screens must not cause side effects that are visible from outside the screen." means is still kind of a riddle.

@zmook Thanks, I know the things about variable declaration, but the part about screen defines and defaults was unclear to me, thanks for mentioning.

Maybe some of you can say what the "screen prediction" actually does and what a "nopredict" screen would not do?

User avatar
zmook
Regular
Posts: 170
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Variables in Screens

#7 Post by zmook » Sun Feb 21, 2021 4:37 pm

"Side effects" are changes in the value of any variable that is not 100% local to the screen, and that is not the screen return value. In this case `count` is visible outside the screen, and the screen can change its value -- that's a side effect.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

User avatar
Alex
Lemma-Class Veteran
Posts: 2727
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Variables in Screens

#8 Post by Alex » Sun Feb 21, 2021 5:31 pm

m_from_space wrote:
Sun Feb 21, 2021 4:18 pm
... My code example was not for showing good programming skills, but how strange variable assignment acts in screens, with different methods. What "Screens must not cause side effects that are visible from outside the screen." means is still kind of a riddle. ...

That means exactly that you shouldn't do

Code: Select all

screen test_scr():
    $ count += 1
'cause it will increase 'count' at each screen redraw (and you can't say how many times the screen will be redrawn) - changing global variable is an effect that visible from outside the screen.
Variable assignment works as intended, but result depends of if you use it properly or not...

You can read about prediction here - https://www.renpy.org/doc/html/screen_o ... prediction

User avatar
zmook
Regular
Posts: 170
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Variables in Screens

#9 Post by zmook » Sun Feb 21, 2021 7:27 pm

Alex wrote:
Sun Feb 21, 2021 5:31 pm
You can read about prediction here - https://www.renpy.org/doc/html/screen_o ... prediction
That says what kind of screens get predicted, but not very much about what actually happens during prediction, other than "load in images that are used by the screen". Does that mean, for instance, that predicting a screen that doesn't load any images is a no-op?

I don't really have any idea when I would use the `nopredict` keyword or the `renpy.stop_predict_screen()` function.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

User avatar
Alex
Lemma-Class Veteran
Posts: 2727
Joined: Fri Dec 11, 2009 5:25 pm
Contact:

Re: Variables in Screens

#10 Post by Alex » Mon Feb 22, 2021 5:52 am

zmook wrote:
Sun Feb 21, 2021 7:27 pm
...I don't really have any idea when I would use the `nopredict` keyword or the `renpy.stop_predict_screen()` function.
In most cases you shouldn't bother about it at all. Using standard functionality doesn't require anything except parenthesis after screen's name.
https://www.renpy.org/doc/html/screen_o ... meter-list

Ren'Py is doing its best to make smoother performance and optimize the memory usage.

You might need to use renpy.start_predict_screen / renpy.stop_predict_screen when you doing something out of standard functionality, something that Ren'Py wasn't designed for. But it requires descent knowledge of python, so if you have it, that shouldn't be hard to check Ren'Py's source code to get how things work...

User avatar
zmook
Regular
Posts: 170
Joined: Wed Aug 26, 2020 6:44 pm
Contact:

Re: Variables in Screens

#11 Post by zmook » Mon Feb 22, 2021 5:04 pm

Alex wrote:
Mon Feb 22, 2021 5:52 am
In most cases you shouldn't bother about it at all. Using standard functionality doesn't require anything except parenthesis after screen's name.
Huh. "When a screen is defined without a parameter list, any name used in that screen can be redefined when the screen is shown." I'm puzzled by what difference this actually makes -- it certainly doesn't stop me from using global variables in the screen.
colin r
➔ if you're an artist and need a bit of help coding your game, feel free to send me a PM

Post Reply

Who is online

Users browsing this forum: Majestic-12 [Bot]