SamSuka
__ess__
__ess__

patreon


Showing dialogue above screens - A small written tutorial

One of the things that can be challenging sometimes in Ren'Py is when you want to show a character dialogue or narration above a screen. In the inventory tutorial I did a while back now, we did some workarounds for it so we could have both the inventory, environment and the dialogue screen showing at the same time.

I thought I'd also show some simple examples of how you could have a scene in your visual novel, which is a screen with clickable items, as well as some dialogue on top of it that can be progressed as the user clicks with the mouse, and also rolled back. This will work for a simple point-and-click game.

This tutorial assumes you're using the latest version of Ren'Py.

In point-and-click games, what usually happens is you have a scene with an environment and some items you can click on. When you do, the character often says something about it. When you click to progress the dialogue, nothing else can be clicked on in the scene which could accidentally end the dialogue too early or do something else.

In Ren'Py that might be a little tricky to do because of how the control flow of the script works.

Since dialogue in Ren'Py usually happens within a label, you have to transfer the user to the label from the screen for the dialogue to show. If you showed the screen using "show screen scene_1" for example,  the screen will stay in place as the dialogue shows on top:

label character_dialogue:
   "Here's a line of dialogue!"

screen scene_1:
   imagebutton idle "some-image.png" action Jump("character_dialogue")

label start:
   show screen scene_1
   return


A problem with this however, is that the "show screen" statement in the start label doesn't transfer control to the screen in question. Instead, when you press "start" nothing seems to happen.

That's because Ren'Py runs that line of the script which shows the screen, and then immediately runs the next line which says "return". This then ends the game and goes back to the main menu. This happens so fast that you can't even tell anything happened.

So to solve that problem, you need to use the "call screen" statement instead. This transfers control to the screen you called, instead of continuing with the next line after the statement.

label start:
   call screen scene_1
   return

So now we fixed that issue, but we get another problem instead. Since we call the screen and then jump to the dialogue label, the screen disappears as the dialogue shows. This gives us a black background with the text on top.

So how do we solve this conundrum?

Well, a way to make this work, is by showing the screen again inside the label with the dialogue. This is done as the first thing to make sure it shows first.

label character_dialogue:
   show screen scene_1
   "Here's a line of dialogue"
   
By doing this, it will seem like to the player that they never left the screen to begin with.

Now after the piece of dialogue has shown to the player, and they click to continue, we don't really have anything so far that will continue the game. As such, Ren'Py will just exit the game to the main menu. But we of course want the player to come back to the screen again, while making it seem like they never left.

For that we add another line of script to the end of the label that calls the screen again.

label character_dialogue:
   show screen scene_1
   "Here's a line of dialogue"
   call screen scene_1

As you can see, by first showing the screen, we allow the script to continue with the next line of script, which is the dialogue. Then when the dialogue is done, we call the screen which transfers control to it, instead of continuing with the code below.

For a point-and-click game, you might have scenarios where you don't know which scene that had an item that the user clicked on. If you have some sort of inventory that the user can interact with to get information about an item they hold, they usually can open the inventory and look at that item in any scene of the game. That obviously makes it impossible to go back to the screen with "show screen" and "call screen" as you don't know which scene they are in.

In order to solve that, you can have a variable that you name, for example "current_scene", and this variable will store what the current scene is. Then every time you transfer the user to a new screen, you set this variable to the name of that screen.

You'd initialize the variable in the start label for example:

label start:

    $current_scene = "scene_1" # Game starts at the first scene.


OR outside of it using 'define':

define current_scene = "scene_1"


Now when you transfer the player to a different screen, you can set this variable to contain the name of the screen they're currently in

For example, let's say you have a screen with a button the user can press to get to another screen (another scene in the game). The action for that button both transfers the user to that screen, but then also sets the variable to the name of that screen, like so:

screen example_screen:
   imagebutton "door-to-scene-2.png" action[Show("scene_2"), SetVariable("current_screen", "scene_2")]

Then inside a dialogue label, you can use the expression keyword with the show and call screen statements and refer to the variable for the name of the screen.

label character_dialogue:
   show screen expression current_scene
   "Here's some dialogue."
   call screen expression current_scene


Now in order to make sure the user can't click any buttons underneath the say screen while it's showing, you might think of adding the modal property for the say screen. This will however make the say screen unable to go to the next line of dialogue, or be closed for that matter when the user clicks with the mouse.

To solve this problem, you can instead add the sensitive property to all screens that are the scenes of the game and UI. With the sensitive property, you can determine whether or not a screen should be able to be interacted with.

The value for the property would be an expression that looks to see if the say screen is showing. If it is, then we make sure the screen is insensitive, meaning non-interactive. You can do that by using the If function available in Ren'Py, like in the example below.

screen scene_1:
   sensitive If(renpy.get_screen("say") is None, True, False)
   ....

You can read about the If function/action here and the get_screen function here

Do this for all screens that shouldn't be able to be interacted with by the user as the say screen is showing.

And that's it. That's one way you can make dialogue show above a screen. 😁

⭐ Hope you liked this tutorial.

Comments

Hello! Thank you for your kind words and for joining my Patreon. Really glad to hear my mini-games are of use to you, always great feedback to get. 😊 Good luck with your projects, and nice of you to choose to credit me in your games, I appreciate it.

Sara

Hello there! I wanted to show my appreciation for the work you do and say thank you! We are a two-person team and becoming a patron and having the option to implement your mini-games helps us greatly on our project. We will be sure to give you due credit for your scripts! :)

Akouo Studios


More Creators