MrValdez's Blog

Coding a Slide Presentation in Ren'py

Posted on Sept. 19, 2020

For PyCon APAC 2020, I would be giving a talk on Ren'Py, a visual novel game engine built on top of Python and pygame. I want to show that Ren'Py is flexible enough that you can make unique games from it. I also like surprising people in my talks.

So I made my presentation as a visual novel.

You can find the source code to my talk here (https://github.com/MrValdez/PyConAPAC2020-renpy) and once PyCon APAC 2020 releases the video, I'll link here so you can see how I gave the presentation.

Subgenre in Visual Novels

There are many styles to visual novel presentations. Two of these are called ADV and NVL. By default, Ren'Py uses the ADVenture visual novels style of presentation where there is a dialogue box at the bottom for characters and the narrator. NVL format is a narration heavy style where the dialogue box is larger, usually taking up most of the screen.

Ren'py supports both ADV and NVL. You can also use both with one game!

How I make a slide in Ren'Py

The key to making a presentation in visual novel is to use NVL mode. Look at the above image for an example of what NVL looks like. Now, think of what a typical presentation look like. We have a header, then text that appears in sequence as the user press a button.

Let's start with looking at how Ren'Py does NVL with a simple example

define text = Character("Noname", kind=nvl,
    color="#0000CC",
)

define text2 = Character(None, kind=nvl,
    font="Helvetica", what_size=30,
)

label start:
    nvl clear

    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    text2 "Hello World"
    text2 "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    return

Each dialogue line is shown as the user clicks or press a key. Feel free to try the above code for yourself.

As you can see, the character's name is shown to the left of the dialogue. If the name is None, the character text is blank. So first thing we want to do is to move the text closer to the left edge of the screen.

init python:
    gui.nvl_text_xpos = 100

For this article, we will be changing the gui settings via python. I do this to make the explanation simpler as you only need to change script.rpy. If you want, you can change the nvl settings under gui.rpy.

Let's see what this code does.

The text have been moved to closer to the left, but the character text remains. Now, we usually don't have a character speaking in presentations, so we simplify our Character definition.

Also, there is a large text between "paragraphs", so we also lessen the spacing

define text = Character(None, kind=nvl,
    font="Helvetica", what_size=30,
)

init python:
    gui.nvl_text_xpos = 100

    # spacing between text
    gui.nvl_height = None
    gui.nvl_spacing = 10

label start:
    nvl clear

    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"

    return

Next, we're going to expand the text so it'll reach closer to the right edge by adding this code:

    gui.nvl_text_width = None

Hmmm. The text went out the window!

There's two solution to this. One is to add \n to long text like so:

    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum\nLorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum\n Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"

Alternatively, you can change the text width to be closer to the window size:

    gui.nvl_text_width = 1280 - 100

Personally, I prefer the former style as I have more control on when to line break.

Next up, the header. Because every slides in presentations seem to have a header. It's a rule or something [1].

Let's add a new character for the header. It will be aligned to the center and will be a bigger text.

define header = Character(None, kind=nvl,
    font="Candara", what_size=50, what_bold=True, what_outlinecolor="#00ff00", what_xalign=.5, what_text_align=.5
)

define text = Character(None, kind=nvl,
    font="Helvetica", what_size=30,
)

init python:
    gui.nvl_text_xpos = 100
    gui.nvl_text_width = 1280 - 100

    # spacing between text
    gui.nvl_height = None
    gui.nvl_spacing = 10

label start:
    nvl clear

    header "Slide 1"
    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"

    return

Now, let's try adding an image into our presentation. Because a picture is worth a thousand words, and we really don't want to make our audience read the slide. [2]

label start:
    nvl clear

    header "Slide 1"
    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"

    show renpy logo

    text "Hello World"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"

    return

First thing you'll notice is that the image is darken. If you look at what an NVL game looks like, you'll see that the text is actually in front of a semi-transparent box. By default, Ren'py puts images in a screen layer behind NVL.

To fix this, we need to put the image on the same layer as NVL:

show renpy logo onlayer overlay

However, this would cause the image to disappear once we go to the next text.

I don't actually know the proper way to handle this. Maybe someone will tell me and I'll make a follow-up article. (You can reach me on my twitter @MrValdez). I just came to the realization that I can actually sidestep this bug by not showing text after the last one.

Next! Notice that the image is tiny and at the bottom? Ren'py have functions to transform images (for more information, look up the Animation and Transformation Language or ATL reference in Ren'py's documentation). Let's apply this to our image:

show renpy logo onlayer overlay:
    zoom 2
    xalign 0.5 yalign 0.7

show renpy logo onlayer overlay:
    size (100, 100)
    xpos 200 ypos 100

Hopefully, the above code are understandable enough.

Showing all of the text

By default, Ren'py would treat each line as a dialogue and will wait for user input. But sometimes, we want to show all the text in the slide at once. We can do this with the no-wait tag or {nw}.

label start:
    show bg

    nvl clear

    header "Slide 1{nw}"
    text "Hello World{nw}"
    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum{nw}"
    text "Hello World{nw}"

    show renpy logo onlayer overlay:
        zoom 1.4
        xalign 0.5 yalign 0.9

    text "Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum"
    return

Look ma, no main menu

If you run the executable, you'll notice that it went straight to the main menu. To remove the main menu, just use the following code:

# override main menu to skip it
label main_menu:
    return

NVL background

Let's see what happens if we add a background.

What's that in the background?

That's the NVL background image. If you look at this NVL game, you can see that it is used for style reasons. Also, it helps distinguish NVL and ADV mode.

You can find the NVL background under the "GUI/nvl.png". If you want to change this, either overwrite the file or change the filename.

We can change the filename by either changing the screens.rpy (just find nvl.png), or updating it when we initialize. If we set the filename to None, no background will be used

init:
    style nvl_window:
        background None

But if we take out the nvl background, the text becomes harder to read (that explains why its there by default). You can make the text readable by changing the contrast for the background underneath, adding a NVL background, or adding an outline.

init python:

    gui.dialogue_text_outlines = [
        (2, "#000000", 0, 0)      # parameters = (Stroke/Outline width, Color, X offset, Y offset)
    ]

How you choose to handle this, is up to you and your artistic skills. (Something I've been lacking as a backend developer)

Done!

And that's it. That's the basics of how I made a presentation using Ren'Py. You should now be able to understand the source code for my PyCon APAC 2020 presentation.

If you find this useful (or at least, fun), let me know on my twitter. And if you gave a presentation with Ren'Py, I would love to hear a video of your talk. :)


[1]: Don't listen to the rules! Experiment what would happen by breaking them! Its the only way to know why that rule exists or if there's a better way. ....just do this safely. Don't do this on production or where people can get hurt.

[2]: A rule of thumb is that if you have a paragraph or two in your slide, and you spend at least 10 second reading the text when presenting, you have too many text. One of my pet peeves is when my students started reading the slides as if it was an essay. I point that out as soon as I can so they can improve their presentation.

Remember: people want you to present, not to read to them. They can do that themselves.

....that said, I did break my rule and read my presentation... but it was to set up the reveal that it is actually a visual novel!

Categories: Programming, Ren'py