Questions on calling a 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
User avatar
SinnyROM
Regular
Posts: 166
Joined: Mon Jul 08, 2013 12:25 am
Projects: Blue Birth
Organization: Cosmic Static Games
Contact:

Questions on calling a screen

#1 Post by SinnyROM » Sun Jul 05, 2015 2:56 pm

I've been reading up on using call vs. show screen and this thread (http://lemmasoft.renai.us/forums/viewto ... =8&t=32951) gave me new insight on how each works. However, I ended up with new questions that may require a new thread depending on where this goes, so here they are!

From trooper6's experiment:
trooper6 wrote:1) Calling the screen does not create a new context. (This is the official programming term context)
2) Calling the screen also does not increase the call stack depth...so it isn't like a regular call. This explains this funny thing I noticed. When I had both the show screen with a return button and the call screen with the return button...I could click out of the call screen and un-pause game flow by clicking on any return button, including the return button on the show screen...not just the return button on the call screen.
I would like to learn as to why calling a screen doesn't create a new context or increase the stack depth.

Here I tried to create a root/sub menu example:

Code: Select all

screen rootmenu():
    frame:
        xalign 0.0
        has vbox
        textbutton "Submenu" action ShowTransient("submenu") #is this the action to call a screen?
        textbutton "Quit" action Return()

screen submenu():
    frame:
        xalign 0.5
        has vbox
        textbutton "Submenu item" action Jump("submenuresult")
        textbutton "Return to root menu" action Return() #expected: go back to the root menu. #actual: jumps to "End"

label start:
    "Rootmenu"
    call screen rootmenu

    "End"
    return

label submenuresult:
    "Submenu item clicked"
    return
I expected to return to the root menu's context, but instead it hides both screens and continues on to the next statement "End".

Is it because I've been misunderstanding the action ShowTransient()? I've been assuming it was the equivalent to Show() but with the inclusion to wait for an interaction to be completed, so it was like calling a screen as opposed to showing it.

Maybe I'm to use this action instead, which is essentially calling the screen with Python?

Code: Select all

Function(renpy.call_screen, "submenu")
Also, labels can call in new contexts, so if I want to call a screen in a new context, does this mean I need to create a label for each screen I want called? Is the only way to call a screen in a new context by using labels or the function renpy.call_screen(), or even renpy.call_in_new_context()?

tl;dr How is calling a screen by itself useful if it doesn't create a new context by default? If possible, how can I effectively call a screen in a new context without resorting to using labels and Python functions?

Sorry for the length, and if it sounds more like rambling, I apologize even further!

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Questions on calling a screen

#2 Post by trooper6 » Sun Jul 05, 2015 6:04 pm

So I'm doing a thing where I'm picking one of the pages in the documentation (or a few elements if the page is a particularly complicated thing) and making a test project where I do everything on the page, then adding cool tricks or whatever else might need to be added that I learn here.

The last tester I finished was for the Screens and Screen Language page. I just did the "high level" stuff, so the subsections: Screen Language, Control Statements, Showif Statements, Screen Statements. And I threw in a few other bits and pieces. One section I did was on Nested screens and returning information. I think the things I'm experimenting with here address what your underlying questions are.

So as to your first question, why doesn't call screen create a new context? I don't know...it just doesn't. But there is probably a good reason for it having to do with what happens when you enter a new context. Xela would know about this more than I would. But looking at the documentation, I notice that renpy.get_game_runtime() only counts time spent in the top level context, so if your calling a screen took you out of the top-level context, it would result in an inaccurate game_runtime stat. Similarly, the tag entry to screen language notes that two screens with the same tag will replace each other in the same context only. So if you had a screen tagged map up and called another map screen and calling resulted in a new context, then that first map wouldn't be replaced...which I also don't think is what is wanted by default.

As to your second question, why doesn't call screen add to the call stack? I don't know...it just doesn't. The documentation for the call statement specifically says that it adds to the call stack: "The call statement is used to transfer control to the given label. It also pushes the next statement onto the call stack, allowing the return statement to return control to the statement following the call." (http://www.renpy.org/doc/html/label.html#call-statement). The call screen statement doesn't mention that at all. So...so...no call stack. But I don't suppose you really need it. When you call a screen it waits for your interaction and then goes back from whence you came...so it is the same effect.

Okay, anyway, here it part of my larger screen tester that deals with nesting screens and passing information back and forth:

Code: Select all

#####
#Calling Nested Screens & Returning Data
#There are only 3 ways to get data into _return: from the return statement, from Return() after using call screen, or when input is invoked using Call Screen

init python:
    class Char():
        def __init__(self, name, mhp, skills=None):
            self.name = name
            self.curHP = mhp
            self.maxHP = mhp
            self.skills = skills
            self.active_skill = None
                
screen battle(char):
    frame align (1.0, 0.0):
        vbox:
            label "[char.name]"
            text "[char.curHP]/[char.maxHP] HP"
            text "Skill to Use: [char.active_skill]"
            text "_return: [_return]"
            text "-----"
            
            textbutton "Choose Skill (with Show)" action Show("choose", char=char)
            textbutton "Choose Skill (with ShowTransient)" action ShowTransient("chooseT", char=char)
            textbutton "Choose Skill (with renpy.call_screen...)" action Function(renpy.call_screen, "choose2", char)
            textbutton "Choose Skill (with renpy.call_in_new...)" action Function(renpy.call_in_new_context, "choosetest", char)
            textbutton "Choose Skill (with ui.callsinnew...)" action ui.callsinnewcontext("choosetest", char)
            textbutton "End Choice" action [Hide("battle")]
  
screen ns_input():
    vbox:
        text "Enter a word."
        input
    
screen choose(char):
    modal True #I added this for my new experiment
    frame align (0.0, 0.0):
        vbox:
            label "[char.name]'s Skills"
            for sk in char.skills:
                textbutton "[sk]" action [SetField(char, "active_skill", sk), Hide("choose")]

screen chooseT(char):#This only hides when the current interaction completes...which means forwarding the text
    frame align (0.0, 0.0):
        vbox:
            label "[char.name]'s Skills"
            for sk in char.skills:
                textbutton "[sk]" action [SetField(char, "active_skill", sk)]
                
screen chooseL(char):#This one if for calling from a lable
    modal True #Put this here if you don't want people to be able to click on the battle screen while this is up
    frame align (0.0, 0.0):
        vbox:
            label "[char.name]'s Skills"
            for sk in char.skills:
                textbutton "[sk]" action Return(sk)
    
screen choose2(char):
    modal True #I added this for my new experiment
    frame align (0.0, 0.0):
        vbox:
            label "[char.name]'s Skills"
            for sk in char.skills:
                textbutton "[sk]" action [SetField(char, "active_skill", sk), Return(sk)]
            
label check():
    "Hello"
    return("Goodbye")
 
label choosetest(char):
    call screen choose2(char)
    "Returning the _return from the choose 2 screen: [_return]"
    return(_return)
    
label start:
    $pc = Char("Tim", 15, ["Attack", "Defend", "Talk"])
    
    "This section of the tester deals with passing information back and forth."
    "Generally speaking a lot of your screens will not pass information around, but set varaibles directly."
    "According to the Documentation, there are 3 ways to return: (which is stored in the _return variable)\n
     -Supplying a varible to the return statement.\n
     -Returned from the Return() screen action *when the screen has been called with call screen*\n
     -Rturned from the Input user interface when placed in a screen that has been invoked through call screen"
    
    "I want to start off with just the passing around of information."
    show screen battle(pc)
    "Do me a favor and don't click any of the buttons on the now showing battle screen just yet."
    "Testing return with expression."
    call check
    "Returning from the check label: [_return]"
    "If you notice, the result of that return is up there on the battle screen."
    $pc.curHP = 10
    "Most of the time though, you'll manually change the variable, like now I'll remove 5HP."

    "Let's do the passing of info from an input."
    call screen ns_input()
    "Notice the change in the return."
    
    "Now let's look at the difference between calling and showing a screen in order to grab input from within this label."
    
    "First the proper way with call. Please choose Attack."
    call screen chooseL(pc)
    $pc.active_skill = _return  
    "The return is [_return]"    
  
    "Now let's try it with show. Show the first way, with a regular manual show. Choose Defend."
    show screen chooseL(pc)
    "First thing to note, the screen didn't disappear. Return doesn't do that if you don't call. So you'd have to add a 
     Hide screen action to the text button in order to hide it. So what did the Return do? It just advanced the screen.
     Click on a button again."
    "The return is [_return]--this is the return from the call. Your button pushing doesn't do anything but have an interaction 
     advancing your text, this is because you showed the screen rather than called it. Click a button one more time so we can
     hide this modal screen." 
    hide screen chooseL

    "So there is another way to show a screen, wait for info, and then get rid of it other, with the ui.interact command. Choose Defend."
    show screen chooseL(pc)
    $result = ui.interact()
    $pc.active_skill = result    
    hide screen chooseL
    "Did I catch a result? I was able to store the result: [result], but it doesn't store it into _return: [_return]"
    
    "Now that we've dealt with returning calling/showing from within the label, let's do it from the screen up there."
    "So click on each of the options and see how it works out. \n
     The first option shows a modal screen that sets the variable directly and then hides the screen. No _return."
    
    "The second option shows the screen with Show Transient. This shows the screen, sets the variable directly (no _return). \n
     It doesn't have a hide function because show transient will hide it with the next interaction..."
    "Which is when you advance the text, not when you press buttons."
    
    "Okay the third button uses the renpy.call_screen funtion...but if you press it, it will throw an error that says:\n
     Exception: Cannot start an interaction in the middle of an interaction, without creating a new context.\n
     So don't press that button! If you want to call a new screen you'll have to use the call in context functions."
    
    "The fourth button uses the modern Function renpy.calls_in_new_context. Note, this calls a label, not a screen.\n
     The label calls a screen that both sets a variable and returns a varaible. You'll notice the _return is caught in the label,\n
     however, because it is a new context, that _return never makes it back to the context of the battle screen, so _return there is not changed."
    
    "The fifth button uses the older and out of fasion version of the fourth button ui.callsinnewcontext. It works the same way as the fourth button."
    
    "The last button closes your screen."
    
    "This section of the tester is over."
    return
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Questions on calling a screen

#3 Post by nyaatrap » Sun Jul 05, 2015 7:24 pm

Code: Select all

why calling a screen doesn't create a new context?
Doesn't it mess up save and rollback? If it's in a new context, it's out of rollback stack.
Also in old ren'py, ui was called like

Code: Select all

python:
    ui.widget()
    ......
    _return=ui.interact()

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Questions on calling a screen

#4 Post by trooper6 » Sun Jul 05, 2015 7:30 pm

nyaatrap wrote:

Code: Select all

why calling a screen doesn't create a new context?
Doesn't it mess up save and rollback? If it's in a new context, it's out of rollback stack.
That too!
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
SinnyROM
Regular
Posts: 166
Joined: Mon Jul 08, 2013 12:25 am
Projects: Blue Birth
Organization: Cosmic Static Games
Contact:

Re: Questions on calling a screen

#5 Post by SinnyROM » Sun Jul 05, 2015 9:55 pm

That screen tester program is an eye opener, trooper6. It really demonstrates the differences between ways of displaying a screen as well as passing variable around. I'm looking forward to seeing the rest of these testers in the future!

I didn't even think of rollback, nyaatrap. I'm used to playing games without it, so it didn't occur to me the side effects of a new context. It makes sense to not create one by default because that might cause more issues than solve them.

Going to play with screens some more, keeping in mind the game flow, although I would like an easier way to call a screen with a new context as an action than having to do Function(renpy.call_in_new_context, "screenlabel") and then creating a label for it. Actually, I'll make a suggestion in the Ren'Py Gripes thread.

Thanks!

User avatar
nyaatrap
Crawling Chaos
Posts: 1824
Joined: Mon Feb 13, 2012 5:37 am
Location: Kimashi Tower, Japan
Contact:

Re: Questions on calling a screen

#6 Post by nyaatrap » Sun Jul 05, 2015 10:09 pm

You can make your own action. Example would be (Not tested):

Code: Select all

init python:
    class CallScreenInNewContext(Action):
        def __init__(self, screen):
            self.screen = screen
        def __call__(self):
            ui.callsinnewcontext("_new_context", screen=self.screen)

label _new_context(screen):
    $renpy.call_screen(screen)
    return

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Questions on calling a screen

#7 Post by trooper6 » Sun Jul 05, 2015 10:10 pm

The tester program (which I think is more or less done...though it could use some more cleaning up and commenting--and I could probably make the basic screen section even more basic), currently has the following sections:
  • "Basic Screens":
    "Screens with 'use' and varaibles":
    "Screens with 'use' and ID":
    "Screens with transclude":
    "Screens with ShowIf, On, default":
    "Creator Defined Screens":
    "Retain After Load":
    "Returning Variables and Nested Screens":
    "Screens with interrupt":
I'm trying to do everything I can think of with each tester in a really methodical and incremental way. I started doing a methodical tester for bars. I learned a lot from that one...but I need to add in vbars and see if I can do some more crazy stuff with them. I decided that I should probably do a bunch of them and then eventually release them in the cookbook section? I currently have: Text and Styles (which needs expansion into more complex stuff), Data Sets (this is mostly Python, but I wanted a collected place where I do all the things I can think of doing with lists, tuples, dicts, sets, and ordered dicts), Screens, and Bars. I want to do each page and then do special testers for all the new python updates.

Anyway, back to your question...is there are reason why you need a new context for your nested screen? You can't use the show modal version?
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
SinnyROM
Regular
Posts: 166
Joined: Mon Jul 08, 2013 12:25 am
Projects: Blue Birth
Organization: Cosmic Static Games
Contact:

Re: Questions on calling a screen

#8 Post by SinnyROM » Sun Jul 05, 2015 10:33 pm

nyaatrap, thanks for the script. I considered it before and I definitely could. I just thought Ren'Py would have something a little easier to access, something I possibly overlooked.

trooper6, those sound like good topics to cover. In the near future I'm actually looking for creative ways with screens and the use statement. I would say the cookbook section is definitely a good choice as I found a lot of useful screen tutorials there.

As for why, I plan to have a battle system with nested menus, something like this:

Code: Select all

Attack
  Target
Use Skill
  Skill Category (eg. Element)
    Skill
      Target
Use Item
  Item Category
    Item
However, using global and class variables to keep track of these and using Show()/Hide() just as in your tester, I got the effect I wanted. Thanks again.

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Questions on calling a screen

#9 Post by trooper6 » Sun Jul 05, 2015 10:40 pm

SinnyROM wrote:nyaatrap, thanks for the script. I considered it before and I definitely could. I just thought Ren'Py would have something a little easier to access, something I possibly overlooked.

trooper6, those sound like good topics to cover. In the near future I'm actually looking for creative ways with screens and the use statement. I would say the cookbook section is definitely a good choice as I found a lot of useful screen tutorials there.

As for why, I plan to have a battle system with nested menus, something like this:

Code: Select all

Attack
  Target
Use Skill
  Skill Category (eg. Element)
    Skill
      Target
Use Item
  Item Category
    Item
However, using global and class variables to keep track of these and using Show()/Hide() just as in your tester, I got the effect I wanted. Thanks again.
You could certainly do the call in new context if you like the effect...but no matter what, you'll end up using globals and SetVariable/Set Field...unless you have some creative use of labels...which, might actually be a good way to do a battle system (*makes notes for later*). So basically, all the different ways I put up there basically do the same thing in the end. And having a Call action I don't think would change the matter.

So basically, what I've come to figure out is that I don't think having a new context actually does anything other than letting you call a label that calls another screen...but that doesn't do anything for you that showing a modal screen and then hiding it won't do.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
SinnyROM
Regular
Posts: 166
Joined: Mon Jul 08, 2013 12:25 am
Projects: Blue Birth
Organization: Cosmic Static Games
Contact:

Re: Questions on calling a screen

#10 Post by SinnyROM » Sun Jul 05, 2015 10:51 pm

True, in the past, modal has been working for me without problems. As long as it prevents the user from clicking elsewhere, my problem is solved! Guess I'll take some time to refactor my variables so they can be easily accessed from my screens.

Oh, the Call action is more syntactic sugar than anything. If it was implemented it would be nice to have! But it's not entirely necessary. I should probably specify that in my other post.

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: Questions on calling a screen

#11 Post by trooper6 » Sun Jul 05, 2015 11:07 pm

SinnyROM wrote:True, in the past, modal has been working for me without problems. As long as it prevents the user from clicking elsewhere, my problem is solved! Guess I'll take some time to refactor my variables so they can be easily accessed from my screens.
Don't forget that now with the most recent Ren'pys you can pass variables and objects into your screens, so that helps a lot with getting access to data. Pass a hero and a villain to your combat screen and you can do most of what you need without making things global.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

Post Reply

Who is online

Users browsing this forum: Ocelot