Ren'Py Examples: Language basics

Page created: 2025-05-28
The Ren’Py mascot Eileen but she is holding a yellow rat rather than a yellow pyton

Back to main Ren’Py examples page

The Ren’Py script language is not the Python language

The relationship between Python and Ren’Py is:

  • The Ren’Py engine and SDK (software development kit) is written in Python using pygame libraries.

  • You can include Python code in your games

  • The Ren’Py script language is similar to Python in having a line-oriented block syntax structure. But it is much more convenient for writing screenplay-like game scripts than raw Python would be.

When you’re writing a Ren’Py game in a file ending in the file extension .rpy, you are writing in the Ren’Py script language.

Including Python code allows you to perform more powerful programmatic actions. You can embed Python within the screenplay-like Ren’Py language.

Fun fact: Python creator Guido van Rossum named "Python" after Monty Python’s Flying Circus, which is a favorite of mine as well.

Image of monty pythons flying circus show logo and cast

Ren’Py script language basics

In a "typical" Ren’Py game, you’ll be writing character dialog and menu choices in the Ren’Py script language.

There aren’t too many concepts in the language itself, so let’s dive in.

Indenting

Like Python, Ren’Py script requires indenting to indicate blocks of code.

You can indent a block with tab characters or space characters.

(It will perhaps amuse you to learn that programmers have been arguing over using spaces versus tabs to indent code for decades.)

Here’s what we mean when we say "blocks" of code:

  block indented with two spaces
  block indented with two spaces

        block indented with eight spaces
        block indented with eight spaces

    block indented with four spaces
    block indented with four spaces

The key thing with indenting is that it has to be consistent. If you indent one line with four spaces, another with two, and then another with a tab, you have caused a sinful insult to the computer (and a situation that will be confusing to you, the human).

If you aren’t consistent about indenting, you’ll see something like this:

File "game/script.rpy", line 14: Indentation mismatch.

A proper text editor is a completely free piece of software and, amongst other things, it will assist you with indenting. (Typically, you can select a block of text and use the Tab key to indent and Shift+Tab to un-indent. (If your editor uses different keys for this, you’re probably using Vim or Emacs and you do not need to be reading this parenthetical.))

Labels

A label is a way of identifying a block of Ren’Py script. It’s the keyword "label" followed by a name and then a colon (":") character.

Everything after the label needs to be indented in order to be considered part of the label.

label foo:
    STUFF INSIDE THE LABEL
    MORE STUFF

STUFF NO LONGER IN THE LABEL

Your game will need a script containing a start label.

If you don’t have one, you’ll get an error. Example:

define e = Character("Eileen")

e "Hello from the dawn of the Universe"

Ren’Py freaks right out with this error message:

ScriptError: could not find label 'start'.

So let’s put in a start label.

define e = Character("Eileen")

e "Hello from the dawn of the Universe"

label start:
    e "Hi, I'm Eileen and this is a Ren'Py script!"
Eileen
Hi, I'm Eileen and this is a Ren'Py script!

Note how the "Hello from the dawn of the Universe" message is not displayed? That’s because the game starts with the start label! Where did that other message go? Best not to think about it.

Jumping to a label

The purpose of labels is to allow you to control how the script flows as the player progresses through your game and makes choices.

The simplest way to get from one block of Ren’Py script to another is with the jump keyword.

define e = Character("Eileen")

label beans:
    e "Have you ever really thought about beans?"

label start:
    e "Hello, I'm Eileen. Is this seat taken?"
    jump beans

Let’s see it in action:

Eileen
Hello, I'm Eileen. Is this seat taken?

Then, when you click to advance the dialog, our jump to the beans block happens and we see the next line of dialog:

Eileen
Have you ever really thought about beans?

Notice how the order of the labels in your script doesn’t matter? Blocks will be called as needed.

For example, the label beans came before start, but we don’t see it until we jump to it.

Quick Aside: Characters and saying stuff

The define e = Character("Eileen") statement in the example above is important and deserves further discussion. For now, know that we have a character named "Eileen" and assigned her to the e variable name. This is a handy shortcut that will cut down on typing (and mistakes)!

A "say" statement does not have to use a pre-defined character.

Here’s an example of saying something with no specified character, and saying something with a character identified by name:

label start:
    "I am a voice from the Beyond!!!"

    "Beyond" "No, actually, I'm Beyond. Who are you?"

Displays character-less "narrator" dialog or text:

I am a voice from the Beyond!!!

And here’s that "Beyond" character identified only by name:

Beyond
Still talking.

Like define, saying things is a topic that deserves its own section, but this should be enough to get you going.

Including Python code in your Ren’Py scripts

There are two ways to include Python code in your scripts.

TODO: There may be a third way, "simple expressions", but I do not understand these yet.

If you have just a single line of Python, you can write it neatly and compactly by starting the line with a dollar sign at the beginning of the line:

$ ONE LINE OF PYTHON

If you have more than one line of Python code, use the block syntax which starts with a python: label followed by any number of lines of Python code.

The code continues as long as the statements are indented.

python:
    PYTHON CODE
    MORE PYTHON CODE

Complete example:

define e = Character("Eileen")

label start:
    e "Hi, I'm Eileen and this is a Ren'Py script!"

    $ say(e, "This is still me talking, but via a line of Python code.")

    python:
        say(e, "And now I'm talking in a Python code block.")
        say(e, "Still talking.")

        say(e, "Also talking here. Still in a Python block.")

Which produces this in-game dialog from the script:

Eileen
Hi, I'm Eileen and this is a Ren'Py script!

And this one from the Python line:

Eileen
This is still me talking, but via a line of Python code.

And these three from the Python block:

Eileen
And now I'm talking in a Python code block.

Eileen
Still talking.

Eileen
Also talking here. Still in a Python block.

It’s probably safe to say that understanding how Python code interacts with Ren’Py scripts will be the subject of most of the examples I’ll be making.