Ren'Py basics
Ren’Py is an authoring system for interactive narratives, originally intended to facilitate the development of visual novels. It has an easy-to-use scripting language that also provides access to the full Python programming language that the system uses under the hood. Ren’Py supports builds for major desktop and mobile platforms and in recent versions even supports HTML5 export. Nifty!
This tutorial goes over the basics of how Ren’Py works, with a focus on the aspects of the scripting language most related (in my opinion) to creating dialogue and branching narratives.
Launcher and project structure
To begin, download Ren’Py and uncompress the files to a convenient location. Start the Ren’Py Launcher application appropriate for your platform. Once the Launcher starts, click Create New Project and follow the prompts.
Creating a new project creates a folder with boilerplate code and assets. The options in the “Open Directory” section of the Launcher will show this folder in your operating system’s file browser.
Code for your project should go in a file called script.npy
. You can edit
this with any text editor. Double-clicking on the file in the Launcher (under
“Edit File”) will open the file in your default text editor.
To run your game, click Launch Project. While the game is running, press
Shift+D
to open a menu that shows various helpful debug scripts.
Something to note about Ren’Py: It’s Python-based, which means that whitespace matters. Indentation marks blocks of code. (In other programming languages, you’d do this same work with curly brackets.)
Labels and text
One of the main ways to organize your Ren’Py games is through the use of
labels. Labels group a sequence of statements that can be jump
ed to (see
below). The only required label in your Ren’Py game is start
. The game begins
at this label.
The following example shows Ren’Py doing the thing that Ren’Py does best: display text to the screen and wait for the user’s confirmation.
label start:
narrator "Hello, world!"
narrator "This is a test."
(Indentation is how Ren’Py groups statements, so make sure to get the indentation right.)
The syntax to display text is <character> string
. The word narrator
denotes
a special built-in character used to show text without attribution. Because
this is so common, Ren’Py just lets you leave this out:
label start:
"Hello, world!"
"This is a test."
Displaying another attribution:
label start:
"Mortimer" "Hello, world!"
"Horatio" "This is a test."
Absent any other statements to control the flow of the game, labels will flow from one to the next:
label start:
"This is a test."
"Nice."
label farmyard:
"Let's go to a farmyard!"
label forest:
"Now we're deep in a forest."
The jump
statement moves execution to the named label:
label start:
"This is a test."
jump forest
label farmyard:
"Let's go to a farmyard!"
label forest:
"Now we're deep in a forest."
(Jumping between labels isn’t terribly useful on its own, but is very powerful when combined with menus; see below.)
By the way, game execution stops when the end of the script is reached, or when
the return
statement is used:
label start:
"This is a test."
jump forest
label farmyard:
"Let's go to a farmyard!"
return
label forest:
"Now we're deep in a forest."
jump farmyard
Also, you can add comments to your code with #
:
# here's where it all begins!
label start:
narrator "Hello, world!"
narrator "This is a test." # so it is!
Menus and jumping
Aside from showing text and waiting for confirmation, the other main user interface element that Ren’Py provides is the menu. A menu presents a number of options and lets the user pick among them. Here’s an example:
label start:
menu:
"Breakfast":
"Delicious bacon and eggs!"
"Brunch":
"Bacon and eggs and mimosas!"
"Lunch":
"Soup and salad special..."
"I hope you enjoyed your meal!"
The menu:
keyword introduces a sequence of options, each indented once. When
the user picks an option, the statements indented beneath that option’s text
are executed. Execution then resumes at the statement after the menu
block.
Menus are especially effective when used in combination with the jump
statement, which causes the game to start executing statements starting at the
named label. This allows you to create simple structures of branching
narrative:
label start:
"Welcome to the hall... of choices"
"Alexandra" "Choose, but choose wisely."
menu:
"Cheese and crackers":
"Ah yes, fancy appetizers! Nothing better."
"Alexandra" "A wonderful choice."
jump cheese
"Fast food burger":
"Sometimes you've got to treat yourself."
"Alexandra" "I'm loving it!"
jump burger
label cheese:
"Alexandra" "Enjoy your brie!"
return
label burger:
"Alexandra" "I'm such a huge Shake Shack fan!"
return
State and conditionals
Statements beginning with dollar signs ($
) are interpreted as Python code.
You don’t need to be a Python wizard to use Ren’Py! But there are a few common
patterns that it’s useful to be familiar with. One of the main ways to use
Python code in your game is to is to set or modify variables, allowing you to
keep track of game state. The default
keyword at the beginning of your script
sets the default value for these variables. Variables set this way are global
and can be used in other labels. The following example presents a menu to the
user and sets variables based on their choice:
default tomato = 0
default funicular = 0
label start:
"Alexandra" "Tomato or funicular?"
menu:
"Tomato":
$ tomato = 1
"You eye the tomato. Its ripeness beckons you."
"Funicular":
$ funicular = 1
"You've always wanted to ride one of these!"
"Neither":
"You're not sure how to decide among such riches. You hesitate."
if tomato == 1:
"Alexandra" "Ah yes, my favorite fruit!"
elif funicular == 1:
"Alexandra" "Enjoy your time on the mountain!"
else:
"Alexandra" "Hmph. You should be more decisive."
The if
/elif
/else
structure at the end of this example is based on Python
syntax (elif
is Python’s way of writing else if
).
These variables don’t have to be numbers; they can contain any Python data type. This example imagines a simple system for tracking character traits using a Python dictionary:
default traits = {'kind': 0, 'smart': 0, 'hungry': 0}
label start:
"Alexandra" "How are you doing today?"
menu:
"I'm well. It's good to see you! How are you?":
$ traits['kind'] += 1
"I am operating within established parameters. You?":
$ traits['smart'] += 1
"I'm hungry. Very hungry.":
$ traits['hungry'] += 1
if traits['hungry'] > 0:
"Alexandra" "You poor soul! Here, have some soup."
else:
"Alexandra" "I'm fine, thank you! Now, down to business."
A very helpful feature for debugging Ren’Py scripts is the console. Type
Shift+O to open it. You can execute arbitrary Python commands in the console,
but a particularly helpful thing to try out is to just type the name of the
variable you’re using to keep track of game state and press Enter. You’ll see
the value that is currently stored in the variable. (Type exit
to close the
console.)
Showing and hiding images
Visual novels are famously… well, visual. So let’s add some visual media to
the game. Ren’Py has a few commands you can use to show images. The first is
the show
command, whose syntax looks like this:
show tag attribute1 attribute2 attribute3 ...
Ren’Py will load an image from the images
folder in your project directory
based on the tag
and attributes that you supply to the show
command. For
example, the following:
show kitty smiling
… would load and display “kitty smiling.png” from your images folder. (Case is ignored when looking for files. Background art, discussed below, can also be supplied in JPEG format.)
Ren’Py will keep an image displayed with show
on the screen until one of the
following happens: (a) the show
command is called again with the same tag
(but different attributes); (b) the hide
command is called with the image’s
tag; (c) the scene
command is called (see below).
I have supplied a file containing a few sample visual assets that you can download and put in your project’s images folder if you want to follow along with the examples below. (You can access your project’s images folder by clicking “images” under “Open directory” in the Ren’Py launcher.)
label start:
show adelaide
"Adelaide" "Hello."
show adelaide glow
"Adelaide" "HOW ARE YOU"
hide adelaide
"Adelaide vanishes in a glowing puff of smoke!"
Images are shown centered in the middle of the screen by default, with the
bottom edge of the image aligned to the bottom of the screen. To adjust this,
you can supply a position to the show
command. The syntax looks like this:
show tag attribute1 attribute2 ... at <position>
… where <position>
can be replaced with left
, right
or center
. (The
technical term for these positions in Ren’Py is transformations. The left
,
right
, center
and truecenter
transformations are built-in, but you can
program your own transformations as
well.)
The hide
command, as mentioned above, hides the image on screen with the
given tag.
An alternative way to display an image is scene
, which hides all other
images currently on screen and the displays the specified image (following the
filename conventions related above):
label start:
scene bg orbit
show adelaide
"Adelaide" "Welp, it was good to see you! Have fun on the surface."
scene bg surface
"The great cratered surface of the planet stretches before you."
Ren’Py comes with a number of built in transition effects, which affect the way that images appear and disappear when you add them to the screen. A full list of built-in transition effects is available in the Ren’Py tutorial. Here’s an example, riffing on the short script above:
label start:
scene bg orbit
show adelaide
"Adelaide" "Welp, it was good to see you! Have fun on the surface."
scene bg surface
with dissolve
"The great cratered surface of the planet stretches before you."
show adelaide
with moveinleft
"Adelaide" "Whoops, you forgot your glasses. Here you go! Bye!"
hide adelaide
with moveoutright
Ren’Py also provides easy commands for playing sounds and video. See the Music and Sound portion of the official tutorial, or the Movie section in the Ren’Py documentation.
Character objects
It’s common in Ren’Py to create Character
objects for each character that
speaks. For more detail about the many affordances of Character
objects, see
the Dialogue and Narration
section from the Ren’Py documentation. For our purposes, making a Character
object has two benefits:
- They’re shorter to type than the character name/text format we’ve been using
so far (i.e.,
"Adelaide" "Hello"
), and let you change the name of the character without having to search and replace every instance of the character’s name throughout the game; - They let you easily change the color of the character’s name when their text is displayed.
Making Character
objects looks like this:
define a = Character('Adelaide', color="#ff4040")
define b = Character('Bernardine', color="#00c000")
label start:
show adelaide
a "Hello."
show bernardine
b "Hi."
Text styles and interpolation
More information on text styles and interpolation.
define a = Character('Adelaide', color="#ff4040")
label start:
scene bg orbit
show adelaide at left
a "How are {i}you{/i} feeling today?"
menu:
"Just rotten.":
$ mood = "crummy"
"Pretty great!":
$ mood = "fine"
a "Hmm, okay. It's good to know you're in a [mood] mood."
a "A {b}very{/b} [mood] mood."