You are on page 1of 30

Before You Begin

There are only two requirements to get started with this tutorial: Download Ren'Py 1. You have to download Ren'Py from the Official Download Page and install it. Think about the story 2. You have to have some idea what the story that you want to tell is. You don't need to have a complete outline, or know all of the characters, though that might be a good idea as a story telling practice (many, though not all, people believe that you should know your entire story at least at a high level before you start to write any of it down). But at a minimum you just need to have a basic idea of at least two characters, a setting, and some idea of where your plot is starting. Planning You can, of course, jump straight into a mega project, but experience shows that one of the main reasons for projects not being completed is that it was just too huge and ambitious. It's a good idea to consciously aim to keep your first project small and simple. As a guide, 5000 words of story-text is usually about 15 minutes of playing time. 30-45 minutes of playing time is a realistic target. Producing art takes a lot of time. While you don't want to let it dictate the story, it's sensible to limit the number of locations (and therefore backgrounds) where you can. Likewise having a large cast will increase the artist's workload dramatically - unless you're happy for the characters to have only one pose and one expression. Just to give you an idea, below are the "profiles" of some completed first-time projects:
Project 1 Creative team: 2 (1 writer, 1 artist) Development time: 1 month (NaNoReNo) playing time: 30-45 minutes Story length: 17466 words Cast: 3 characters, 38 sprite images Story world: 15 backgrounds (filtered photos) Music: none. Project 2 Creative team: 1 person Development time: Playing time: 30 minutes (but had shoot-em-up elements) Story length: 8000 words Cast: 3 characters, 45 sprite images + 3 minor characters Story world: 12 backgrounds, plus rendered spaceships Music: from the web. Project 3

Creative team: 1 person Development time: 2 months Story length: 1507 words, Only one ending (kinetic). Cast: 3 characters. Everyone has only one pose. Main character has 7 expressions, while the others have 4 and 1. Story world: CG and 4 painted backgrounds Music: 3 tracks from the web.

And a major project just for comparison:

Project 4 Creative team: 2 people (artist/writer, musician) Development time: 2 YEARS Story length: 51756 words, 6 main endings plus a couple of "you die" dead ends. Cast: 9 characters, 65 sprite images Story world: 86 backgrounds (50% filtered photos) Music: 8 tracks, composed for this work

So you see, projects can be as big or as small as you like. Start making your game That's it. You're now ready to get started.

Getting Started
Once you've installed the latest version of Ren'Py, run the Ren'Py launcher. On Windows, this is renpy.exe. On linux, you run the script renpy.sh in the installed renpy directory. Click on the "New Project" button. Click on the "template" button. The launcher will prompt you for a name. Enter a simple, preferably one-word name for your project. If you can't think of anything, "renai1" will work. Then hit enter. This should bring you back to the main launcher page, except now it will say the name of your project in the upper left-hand corner. Click on the "Edit Script" button. This will launch the jEdit text editor with your new Ren'Py script (which is currently the same as the Ren'Py template script). If you're not on the "script.rpy" tab, please pay no attention to the current tab and switch to that one. You're now ready to go.

Thinking in Ren'Py

Ren'Py Is Easy Ren'Py is probably the easiest way to write visual novels that exists. Yet many people who see a Ren'Py script for the first time are scared. How can this be? The answer is simple: Ren'Py is designed to make writing complete visual novels as easy as possible. It's not designed to make starting visual novels as easy as possible. What's the difference? A visual novel is a long and fairly complex story. An easy tool for small projects often gets in your way on large projects. Consider a hand trowel and a shovel: if you want to plant a petunia in a window box, the short handle and small spade of a trowel make it easy to handle. But if you want to dig a hole in your back yard to plant a tree, the long handle and big spade of the shovel will let you finish in 1/10th the time and effort. It's not that either one is easier than the other: they're each easier for the problem they're meant to solve. And let's not kid ourselves: writing a visual novel is much more like planting a tree. A visual novel which takes only half an hour to play might easily have 10,000 words and several branches in it. Writing 10,000 words of a story which branches and recombines is real work. Some of the games made with Ren'Py have 30,000 words. Professional visual novels have 100,000+ words. That's a lot of work. The goal of Ren'Py is to require as little extra work as possible. That's why Ren'Py might seem a little scary at first. The features of Ren'Py which make it as easy as possible to deal with a 50,000 word visual novel may seem unnecessary when you've only written 50 words. If you keep writing, it will seem necessary soon enough. So, even if Ren'Py might look a little scary right now, please trust us that Ren'Py is the easiest way to write a visual novel. Because if you start, pretty soon you're going to be wrestling with your plot and characters and the choices and the branches, and the Ren'Py script will be so natural when dealing with them that you'll barely notice it. (originally written by Chris Lansdown) Programming You don't need to know any programming, or be able to program, to use Ren'Py. It is, however, true that even a basic Ren'Py visual novel requires a few programming statements in python. Don't worry about this. In this tutorial we'll show you all of the python statements that you'll need to use, and you'll be able either to copy them directly or copy them and modify the names or filenames, and where that's relevant, we'll explain how to do it. You won't need to understand python code at all to write a visual novel; you'll only need to be able to copy and paste it. If you are a programmer, or have a programmer on your team, you can go to the trouble of understanding the python that you'll need, but it probably won't win you much. On the other hand, if you want to use the python to do something unique and cool, we will provide links into the reference manual so you can do this if you want. Indentation The biggest problem with computers, and consequently with Ren'Py, is that they're not intelligent. Computers can't understand human communication, so we have to do all of the work to make the computer understand us. It's not fair, but in any relationship the one with less to lose always wins. Since the computer is an inanimate object, it has nothing to lose at all.

So we need to figure out ways to communicate with the computer that the computer understands. Most of the time this isn't too bad. For example, we use variables to hold values. We're used to giving things names, so this doesn't strain us very much. Writing something like:
$ gift = "swimsuit"

might be unusual, but it's just a formalized way of doing what we're used to doing. In this case, it's the same thing as saying, "I'm buying the swimsuit for my girlfriend", except in computerish rather than in English. So far, so good. The big problem with communicating with computers is context. We're so used to dealing with this that for most people it's unconscious. When you say "I tipped the waiter" and "I tipped the cow", you know that in the first one "tipped" means that you gave the waiter money and in the second one it means that you pushed the cow. You know this because of context: you normally give waiters money, but rarely push them over, whereas cows have no use for money. Computers have no concept of context, so we have to come up with some way to fake it. Ren'Py uses is indentation as its solution to this problem. Indentation is the amount of "white space" (spaces) before the words on a line. For example:
"This line isn't indented." "This line is indented 4 spaces." "This line is indented 8 spaces." "This line is also indented 4 spaces." "And this line is indented 12 spaces." "Whereas this line isn't indented at all."

In Ren'Py, we use this to give the Ren'Py engine context, so it can figure out what we mean. All of the statements next to each other with the same (or greater) indentation are in the same context. We call all of these statements a "block". For example, in a bit we'll talk about "init blocks". This just means all of the lines which are indented after an init statement:

init: # This is in the init block # this line is also in the init block # this line is NOT in the init block

It's also possible for blocks to be nested in each other like those russian dolls that open to reveal a smaller doll:

init: # This is in the init block # this line is also in the init block python: # this line is both in the python block and the init block # as it's written here, it's not possible to be in the python block # but not the init block. # this line is still in the init block, but not the python block, so # we say that the python block is "closed", since no more statements # can go in it. But we can still put statements in the init block. # this line is NOT in the init block

Don't worry about getting the hang of indentation and blocks now, it will make a lot more sense as you continue reading the tutorial and see real examples. Conveniently, you don't need to understand it before then, either. :)

Ren'Py Script Structure


Init Blocks Every Ren'Py script has information, such as characters, images, and music which you need to declare outside of the story. This is done with init blocks. An init block looks like this: init: $ john = Character("John Smith") $ percy = Character("Sir Percival Blakely") image black = "#000000" Later sections will explain what goes in the init block, for the moment we're just pointing out what they look like. They can come anywhere in a file, but it's generally best to put them at the top. Init blocks are not indented, and the statements following an init block which are indented are in that init block. Once you type a statement (usually a label) which is not indented, the init block is finished. You can have any number of statements in an init block. And that's all you need to know about them for now. Labels Labels allow you to give names to points in your story. Using them to change the flow of your story is discussed inBranching & Recombining the Story. Right now, the important thing to know is that every Ren'Py script has to have one label in it, called "start". That's where Ren'Py starts executing your story. It looks like this:
label start:

So, generally, the beginning of a simple Ren'Py script would look like:
init: $ j = Character("John") label start: j "Hello, World!"

Comments You will occasionally see comments in a Ren'Py script explaining what a line in the script is for. Comments look like this:
# lines that start with an octothorpe (a.k.a. a number sign, # hash, or sharp) are comments. If you want to have comments

# continue over several lines, you have to put the hash mark # at the start of each line.

People playing Ren'Py games never see comments, they're only for you and anyone collaborating with you on a Ren'Py game. Ren'Py ignores comments, so you can put anything that you like in them. They're also useful for removing lines from the story which you're not ready to lose forever:
# j "Nice shoes, Jen."

Multiple files
As your game gets bigger, you might decide to split the game file up, to make it easier to find things without all that scrolling. You can call the files whatever makes sense to you, but they must be in the "game" folder for that project, and must end with the extension ".rpy"

Defining Characters
Characters in Ren'Py are very powerful objects, but in common practice they're very easy. (If you want to get into the really powerful stuff, check out the Defining Characters chapter of the reference manual.) (Please note through all of these examples that characters must be defined inside of an init block.) The simplest way to define a character is:
init: $ jane = Character("Jane")

In practice, this is a little too simple. You should choose a color for the character's name. You do this by a standard red-green-blue hex triplet: #rrggbb. To make Jane's name appear in medium green:
init: $ jane = Character("Jane", color="#009900")

A useful color chart may be found here. Still common, but less so, is to use an image in place of the name. To do this, instead of giving jane a name, you give the filename of an image (placed in the game directory of our Ren'Py project), and tell Ren'Py that the name is really an image:
init: $ jane = Character("jane_label.png", image=True)

The other common thing that you might want to do with characters is to make the text that they say appear in a different color. This makes both the label and the text for whatever Jane says appear in medium green:
init: $ jane = Character("Jane", color="#009900", what_color="#009900")

When defining characters with more than a few lines, it's a good idea to make the Ren'Py name of the character as short as possible. So rather than:
init: $ jane = Character("Jane")

it's better to write:

init: $ j = Character("Jane")

It will save you a lot of typing in the long run, and is usually just as readable when you're editing your story. When definining more than one character, don't forget that they only have to be in an init block, you don't need an init block for each one:
init: $ j = Character("Jane") $ a = Character("Adam") $ s = Character("Sara")

Your First Dialogue


Basic Dialogue Dialogue in Ren'Py is extremely easy. Once you've defined a character, you simply prefix their dialog, in quotes, with their name:
bob "Hi Alice!" alice "Hi Bob!"

For characters who have very little screen time, you don't need to create a character for them if you don't mind their dialogue appearing in the default style:
bob "I wonder who this man approaching us is." alice "I don't know, but he looks tough." "Tough Guy" "Yo. Whaddup?" bob "Hello." "Tough Guy" "I'm oudda here." bob "That was strange."

Narration
Narration is simply dialog without anyone saying it:
"The brief appearance of that tough guy left me feeling uneasy. Was it one of the rival noodle companies trying to intimidate me?"

Spicing Up Your Text You can spice up your text using text tags:
"Text tags let you render parts of a dialogue or narration in {i}italics{/i} or {b}bold{/b}."

Text tags can do a lot of other things as well, check out the reference manual page on Text Tags for more information. A word to the wise: text tags can be effective if used sparingly, but if used often they can make text painful to read.

Adding Graphics to Your Story


Initializing the Graphics The first step in using a graphic image is to tell Ren'Py about it in an init block with an image statement. You create a Ren'Py image from either solid colors or files (really, any Displayable):
init: image image image image image

black = "#000000" bg park = "park.jpg" eileen happy = "eileen1.png" eileen sad = "eileen2.png" eileen surprised = "eileen3.png"

As you see, image names can be more than one word. We'll talk about why this is useful in the section on hiding images. Image names and character objects don't have anything to do with each other, so you can re-use character names as image names. Showing graphics before the game begins If you want to show a picture before the player gets to the main screen, then use the label "splashscreen" like so:
label splashscreen: show opening picture name $ renpy.pause(2.0) return

The line "$ renpy.pause(2.0)" will show the picture for two seconds. Change the number if you want to show it for a different time. If you leave the brackets empty, so:
label splashscreen: show opening picture name $ renpy.pause() return

Then Ren'Py will show the picture until the player clicks the mouse or presses "Return". Scene Backgrounds The scene statement clears the display of what's on it and optionally places a new background on the display:
scene bg park

(Please recall that "bg park" is the name of the image; bg is not a keyword.)

Character Graphics Character graphics and other objects which are drawn in the foreground are displayed with the show statement:
show eileen happy

A show statement without any modifiers shows the image centered in the screen. You can also display images on the sides:
show eileen happy at right show eileen happy at left

Custom positions Ren'Py already has some standard positions defined, but inevitably there will come a time when you want to position an image in a specific place. You do that by using Position:
show eileen happy at Position(xpos = 0.5, xanchor=0.5, ypos=0.5, yanchor=0.5)

xpos describes a point on the background to Ren'Py in terms of how far it is from the left-hand edge. If you use a whole number (e.g. 129) Ren'Py will assume you mean pixels. If, as above, you use a decimal number between 0 and 1, Ren'Py will calculate it as a proportion of the width. So 0.25 would be interpreted as "a quarter of the way across the background from the left." xanchor describes a point on the image you want to position, again in terms of how far it is from the left hand side. Just as in xpos above, use a whole number to count pixels, or a decimal between 0 and 1 if you want to describe it as a proportion of the width. Ren'Py now will show the image so that the xpos and xanchor points are in the same place. Reduce the xpos value to move it left, increase the xpos value to move it right. ypos and yanchor follow exactly the same rules, describing to Ren'Py how far the point is from the top of the image. (So to move an image down, you need to increase the ypos value.) If you're going to use a custom Position more than once, then you can give it a name, like so:
init: $ gardenpath = Position(xpos=0.5, xanchor=0.5, ypos=0.5, yanchor=0.5)

Then you can use it just like any pre-defined Position:


show eileen happy at gardenpath

Overlapping images When an image is added to a scene, Ren'Py adds it on its own, separate layer. By default each new layer is added on top of the ones which already exist. Most of the time images added to a scene do not overlap, so it doesn't matter which layers they are on. However if you want to add the appearance of depth to a scene, then an easy way to do this is to partly overlap the images. The player will interpret a larger image on the topmost layer as closest to their viewpoint, and a smaller image drawn partly behind it as further back into the scene. Imagine for a moment that we've made a background picture of a house with a garden, and we want to show two characters: one in the foreground and one a little way behind that, who will appear to be halfway up the garden. In a real game you'd probably want to make custom positions for these images, but for simplicity, imagine that they're drawn so that they'll be correctly positioned when they're displayed in the default position. Having the characters overlap correctly is no problem when beginning a new scene:
scene bg houseGarden show distantChar show foregroundChar with dissolve

However if the scene is already showing, and we want distantChar to appear (perhaps having just come out of the house), then:
*** Wrong! *** scene bg houseGarden show foregroundChar with dissolve "The sounds of argument in the house cease and distantChar comes running out into the garden." show distantChar with dissolve *** Wrong! ***

The code above will not give the effect we want: distatChar will be added to a layer above foregroundChar, and so the overlapping will be the wrong way round. The way to get the effect we want is to use the behind keyword like this:
... "The sounds of argument in the house cease and distantChar

comes running out into the garden." show distantChar behind foregroundChar with dissolve

Now the images are correctly overlapped. You don't have to worry when you're using "show" to replace one image of a character with another. Ren'Py will automatically place the new image on the same layer where the old one was. Hiding Graphics Hiding graphics which were displayed with the show statement can be accomplished in three ways: Explicity First, you can explicitly hide a graphic which was shown using the hide statement:
hide eileen

If an image consists of more than one word, you only need to tell the hide statement about the first word (the "image tag"). This means that you don't have to keep track of the version of the character graphic that you've shown most recently. Implicitly with show The show statement will automatically replace the image with the same image tag which us currently being shown (though not quite in the same way as a hide statement). For example:
show eileen happy e "I'm happy." show eileen sad e "Now I'm sad."

does the right thing you don't get two copies of eileen on top of each other. Implicitly with scene The scene statement clears all images off of the screen, so if you're changing scenes you don't need to hide anything first.

Special Effects All of the statements which show and hide images can be modified by adding a with clause (see: with statement):

scene bg park with fade show eileen happy with dissolve

There are many special effects available, but those are the two most commonly used. (It seems like only George Lucas can get away with stuff like side wipes, but if you want to try, you can check out the full list of Pre-Defined Transitions.) Getting What You Want to Happen, to Happen Neither the scene statement nor the show statement, on their own, immediately display to the screen. Rather they queue images up, so if you combined them:
scene bg park show eileen happy show ted happy at left

it will display all at once. The with statement and clause both change this. So if you wrote this:
scene bg park with fade show eileen happy with dissolve show ted happy at left with dissolve

Ren'Py will first fade the background in, then dissolve eileen onto the screen, then dissolve ted onto the screen. To get a single fade into the new background with eileen and ted on it, use the statement form of "with" after you've told Ren'Py what you want on the screen:
show show show with bg park eileen happy ted happy dissolve

(Please note: for historical reasons, this is not the same as:
show bg park show eileen happy show ted happy with dissolve

Which will cause the background and eileen to display without a transition and then show ted with a dissolve transition. In general, if you're using more than one statement, only use the with statement on its own line.) As a result of the show statement's queueing behavior, this won't work:
show eileen happy show eileen sad show eileen morose

show eileen elated

the reader will only see the last one. If you want to show several versions of a character without interacting with the reader, you need to use the with clause to get them displayed:
show show show show eileen eileen eileen eileen happy with dissolve sad with dissolve morose with dissolve elated with dissolve

Giving the User a Choice with Menus


Menus are implemented the menu statement, which is probably best explained by an example:
menu: "Choice 1": "This is the result of the user choosing choice 1" bob "Hi Sarah." sarah "Hi Bob." "Second Choice": "This is the result of the user choosing the second choice." "The third menu option": "This is the result of the third menu option" bob "What up, Sarah?" sarah "Yo yo yo." "The fourth option doesn't do anything if you pick it": pass "The fifth option is a little different": bob "Hi Sarah. Hey, could you give me your sister's phone number?" sarah "Um, she doesn't have a telephone."

Menu choices can be as long as you like, and you can have as many of them as you like, provided that they can all fit on the screen. The results of menu choices can also be as long as you like, without restriction. Every line that's the result of a menu choice must be indented beyond the menu choice. Please note that every menu option must have at least one statement, so if you want the menu option to do nothing, use the pass statement.

Remembering User Choices


Changing Game Flow Based on Earlier Choices You can remember user choices by assigning to variables. For example:
menu: "Buy her an Iguana": $ gift = "iguana" b "I'll take an iguana, my good man!" "Buy her a Corn Snake": $ gift = "corn snake" b "I'll take a Corn Snake, my good man!" "Buy her a tortoise": $ gift = "tortoise" b "Give me your slowest tortoise, please!"

Please note that a single "=" is used to assign a variable. Later in the game, you can then use the if statement to change the script based on the previous choice:
b "Open it, Mary." if gift == "iguana": m "Oh Bob, I've always wanted an iguana!" if gift == "corn snake": m "Oh Bob, I needed a corn snake that matches my red dress! Thank you so much!" if gift == "tortoise" m "Bob! It's so slow! I love you!"

Please note that the double "==" is used to test for equality. You can call your variables anything that you like, as long as it doesn't conflict with keywords or character objects. The only rule with variables is that you have to assign to a variable before you can use it in a conditional. Showing or hiding menu options Often, when you get to a particular point in a game, you'll want to tailor the options offered to the player depending on what they've chosen to do earlier in the game. Let's imagine that Bob and Mary are going out on their second date, and the player gets to choose between the Park and the Cafe - unless Bob gave Mary the tortoise as a gift, in which case they can go to the Tortoise Land Speed Trials! Here's how:

b "So, where would you like to go, Mary?" menu: "I'd like to go to the park!": jump park_date "I'd like to go to the cafe!": jump cafe_date "Can we go tortoise racing?" if gift == "tortoise": jump tortoise_racing

(Notice the two equals signs "==" between gift and tortoise.) The menu choice for tortoise racing will only appear when the result of the "if" test is true. If Mary was given a snake or an iguana, then the player will only be able to choose the park or cafe dates. This system can be easily adapted if you want to have the player returned to a menu, but to hide the options(s) which have already been chosen. First create the variables which the game will use.

$ park_date_done = False $ cafe_date_done = False $ tortoise_date_done = False

Notice that we use a single equals sign "=" because we're setting a value. Two equals signs "==" are for testing a value. The names of variables can be any length you like, but can't contain spaces. The longer a name, the more descriptive it is, and so the easier it is to tell what it's for when you look back at your script in a few weeks, months or year's time. Of course it's also more typing, so it's worth choosing short names for variables that you'll use a lot.

... label date_choice: b "So, where would you like to go, Mary?" menu: "I'd like to go to the park!" if park_date_done == False: $ park_date_done = True jump park_date "I'd like to go to the cafe!" if cafe_date_done == False: $ cafe_date_done = True

jump cafe_date "Can we go tortoise racing?" if gift == "tortoise": jump tortoise_racing "Let's just go home" if park_date_done ==True: jump date_over label park_date: b "Well, here we are, at the park!" m "Yes, it's very interesting. Can we do something else now?" jump date_choice label cafe_date: m "Gee, what an exciting cafe!" jump date choice label tortoise_date: # WRONG! should be date_choice

# WRONG! Ren'Py will complain about this until you # correct it to "tortoise_racing" m "Well! A whole lot of tortoise-related fun!" b "Yeah, great." jump date_choice

label date_over: "... and the game goes on from here." etc.

The park and cafe dates can only be chosen once, because Ren'Py changes the value of the variable concerned after the player chooses that option. At the end of that date, the "jump" instruction takes the player back to the date-choosing menu. However, the lucky couple can go tortoise racing as often as they want, because Ren'Py isn't told to change the value of "tortoise_date_done." (That variable is just wasted, although Ren'Py won't complain.) Notice that you have to have at least one "Exit" option that doesn't loop back to the menu, otherwise the player will get stuck. The "Just go home" option will appear after they've been to the park, because choosing the park option changes the variable the "Just go home" option tests. Be careful not to make the "Exit" option the tortoise choice - otherwise players who gave iguanas or snakes will likewise be stuck, since that option won't show up for them. Implementing a Point-Based Game

A point-based game is one in which the choices that a user makes at menus cumulatively change the story after many of them have been made. First, you'll need to decide what you want to be able to gain points for. For example, you might want the user to be able to win points by (1) building big muscles (strength) (2) learning to juggle large numbers of objects (dexterity) and (3) performing chemical experiments and creating increasingly advanced forms of life (mad science). Next, you'll need to initialize the variables that you're going to use to keep track of these points. You do this immediately after the start label:
label $ $ $ start: strength_points = 0 dexterity_points = 0 mad_science_points = 0

During the game, you'll present the user with choices that affect these points, and then modify the variables based on the choices. To increase the points, use:
$ variable += 1

(That's plus followed by equals.) You can use any number, it doesn't have to be 1. To decrease the points:
$ variable -= 1

(That's minus followed by equals.) You can again use any number, not just 1. For example:
menu: "Go to the gym": $ strength_points += 1 "The gym was hot and sweaty." "I picked up heavy things, then put them down again." "I always wonder why I bother, since I could achieve the same thing by not picking them up in the first place." "Practice juggling balls": $ dexterity_points += 1 "I practiced juggling seven balls." "It was hard, but I finally managed to get it at least once." "Practice juggling angry porcupines": $ dexterity_points += 3 $ strength_points -= 1 "Practicing with angry porcupines really sharpened my reflexes. Unfortunately, I'm feeling weak from blood loss." "Invent a happy porcupine": $ mad_science_points += 1

"Unfortunately I was only able to create a melancholy echidna, but I learned a lot and I was sure that next time would be better."

(You can of course customize the responses based on the current points, using the techniques outlined in the earlier section on variables.) Finally, customize your ending using the variables:
if strength_points > max(dexterity_points, mad_science_points): "You pick up a cow and jump over the moon." elif dexterity_points > max(strength_points, mad_science_points): "You juggle 215 balls and set the world record." else: "You create the perfect companion and retire with it to the castle built by the army of servile eight-armed giant gorilla-men you created earlier in the day." return

The above code decides ties in favor of the last option (mad science). If you would like to be explicit about how to handle ties, it's more complicated, as there are seven possible conditions, but still quite doable. It looks like this:
if strength_points > max(dexterity_points, mad_science_points): "You pick up a cow and jump over the moon." elif dexterity_points > max(strength_points, mad_science_points): "You juggle 215 balls and set the world record." elif mad_science_points > max(strength_points, dexterity_points): "You create the perfect companion and retire with it to the castle built by the army of servile eight-armed giant gorilla-men you created earlier in the day." elif strength_points == dexterity_points == mad_science_points: "Your band of servile sixteen-armed giant gorilla-men built you three castles, which you juggle to impress the perfect companion you created earlier in the day."

elif strength_points == dexterity_points: "You juggle three large boulders and many attractive people of the opposite sex swoon." elif dexterity_points == mad_science_points: "You invent a species of round humming bird, and juggle 5,000 of them at once." elif strength_points == mad_science_points: "You invent a 30 ton 24-armed gorilla man, and then pick him up so that he can paint the top part of the house he's building for you." return

The ordering of the conditions above is important, because later alternatives assume that previous ones have been false. In general, you want to first test if any single variable wins, then test if they're all the same, then test to see which ones tied. This strategy avoids several possible pitfalls in the game logic.

Branching & Recombining the Story


Short branches can be accomplished entirely with the menu statement by including the entire branch indented after the menu option. For longer branches, however, this will get cumbersome. The solution is to use labels and the jump statement or the call statement. The first thing that you'll have to decide is whether you're going to use call or jump. Jump simply changes where in the script Ren'Py is executing, and that's it. The new place of execution in the script can only move forward; there's no such thing as returning from a jump, though you could always jump to a label after the original jump. Thus you can't easily re-use jump-branches from multiple places in your script. For a visual novel, jump will probably be sufficient. Call, by contrast, saves information about where you were, so that the branch being called can automatically return to the right place. With call, you can easily re-use branches. Dating sims will probably want to use call. You can, of course, use both types of branching in the same visual novel (or dating sim). Mixing and matching is fine, so long as any single branch is only either a call-branch or a jump-branch.. Branching with Jump The first step of branches using jump is to mark places in your script using the label statement:
label jewelry_store: b "Let's go to the jewelry store. I'd like to buy you something." s "You're so sweet!"

Next, you add the jump to the branch:


s "What do you want to do?" menu: "Let's go to the jewelry store": jump jewelry_store #we'll never go past the jump statement, since it doesn't return "Let's do nothing": s "This is boring."

Congratulations, you've branched with jump! Unless this branch runs to the end of the game, you will probably want your branch to jump to other places in the script. This is done in the same way; branches are not special and you can jump to anywhere you want even though you're in a branch. For example, suppose that in the above example you want to go back to after the menu from the branch. First, you add a label after the menu so that you have somewhere to jump to: s "What do you want to do?" menu: "Let's go to the jewelry store": jump jewelry_store #we'll never go past the jump statement, since it doesn't return "Let's do nothing": s "This is boring." label what_to_do: b "Well, now what?"

Then you add a jump to the end of the branch:


label jewelry_store: b "Let's go to the jewelry store. I'd like to buy you something." s "You're so sweet!" b "I am." s "Well, that's enough. Let's go back." jump what_to_do

Please note that labels have to be unique within a Ren'Py script. Branching with Call The first step of branches using call is to mark a branch in your script using the label statement and the return statement:
label jewelry_store: b "Let's go to the jewelry store. I'd like to buy you something." s "You're so sweet!" etc. return

(NOTE: it's very important that a call-branch should never be entered either with a jump or by normal script flow. If it is, the return statement at the end of the branch will cause the game to immediately end. A return statement outside of a call is actually the correct way to end the game: the metaphore is that since the game came from the starting menu, a return statement in the main story would go back to the starting menu.) Next, you add the jump to the branch:
s "What do you want to do?" menu: "Let's go to the jewelry store": call jewelry_store s "That was fun" "Let's do nothing": pass

Congratulations, you've branched with call! Unfortunately, you're not done. You don't need to do anything while you're still writing your game, but when you're ready to release your game, you'll need to run the "Add From to Calls" tool in the Ren'Py launcher to add labels below your call statement and from clauses to all of your call statements. Reaching the End Your story may have more than one ending, or just a single ending. Games with just a single ending and no choices are often called Kinetic Novels rather than Visual Novels, just for clarity. Regardless, when the player gets to the end, you'll probably want to make it a bit of a special event. Perhaps with a specially drawn picture or an animation, but at least a screen saying "THE END". If your game has more than one ending, it's worth considering giving each ending a name, or at least numbering the endings. This helps when people are discussing your game, since they can be sure that they're talking about the same ending without having to actually describe it (and so risk giving out spoilers.) Imagine your story is about characters getting together and planning a party. You've a lovely finishing image of all your characters whooping it up, which you declared in the usual way:
init: image party ending = "party.jpg"

If your ending has a line of text being shown, the ending scene is really easy to write:
"Chris smiled."

c "Well, that seems to be that!" scene party ending "And everyone partied happily. return

\n\nEnding 3 - Neighbourhood Party"

The "return" tells Ren'Py to go back to what it was doing before the player started playing which was showing the main screen. Ren'Py always waits for a response from the player when it shows text, so this works fine. However, if you want to show an image without having part of the screen taken up with the dialogue box, then there is a problem. If you write:

"Chris smiled." c "Well, that seems to be that!" scene party ending return

Then you will find that the party image will be shown only briefly before the game returns to the main screen. We need to tell Ren'Py to pause so that the player can enjoy the art. Happily that's easily done: the instruction is $ renpy.pause(). Like so:
"Chris smiled." c "Well, that seems to be that!" scene party ending $ renpy.pause() return

Now the picture will be shown until the player clicks the mouse. A Note on Organization There is no consensus on the best way to organize branches. It is, however, recommended that you come up with some way to organize your branches and stick to it.

If you use multiple files to organize your script, please bear in mind that labels are visible from any file, so jumping to a label in a different file is exactly the same as jumping to a label in the same file. Since labels have to be unique in a Ren'Py script, this means that you can't re-use labels in different files of the same Ren'Py game.

Chapters
Just like a traditional story, you might want to divide your Visual Novel up into chapters (or Acts, or any other story-telling chunk which makes sense in the context of your work.) Here's how.

scene black with dissolve show text "Chapter 1\nA Frightening Sight" with Pause(1.5) scene black with dissolve scene your_scene_title e "And now the story really begins."

The code above will cause Ren'Py to fade to a black screen, showing "Chapter 1" centered on the screen, and below it on the next line "A Frightening Sight", also centered. (The "\n" means "new line".) After a pause of 1.5 seconds, the text will fade out again. If you just say:
show text "Chapter 1/A Frightening Sight" with Pause

then "Chapter 1" etc. will stay on the screen until the player clicks or hits Return. "black" (note the lower case "b") is the only color which Ren'Py knows about by default. If you want to use a different color as the background for your chapter titles, then you'll have to set that up before you can use it, in an init block, like so:
init: image black = Solid((0, 0, 0, 255)) image white = Solid((255, 255, 255, 255)) image grey = Solid((128, 128, 128, 255))

Just google for "web colors" if you don't know what the values in brackets should be for the color you want. Note that there's nothing special about this "Chapter scene" - you don't have to use a Solid color if you don't want to. A custom scene-title .jpg would work just as well.

Adding Music & Sound Effects


Music To play background music (which loops until you stop it), you use the play statement:
play music "ominous.ogg"

To use fade-in or fade-out (in seconds):


play music "ominous.ogg" fadein 2 fadeout 2

To stop the background music, you use stop statement:


stop music

Sound Effects To play a sound effect, use the play statement:


play sound "bang.ogg"

There's a Ren'Py function to stop sound, but there's usually no reason to use it. Voices (Voice Acting) If you want to add voice acting to your visual novel, you'll need to put each screen of dialog into a separate file, and name them in a way that you can figure out which line of dialog they go with. Then, before each line of dialog, put avoice statement:
voice "bob203.ogg" bob "I love ice cream." voice "nancy218.ogg" nancy "I love ice cream too." voice "bob204.ogg" bob "I also like cookies."

You might also like