Basic Ren’Py Tutorial #1: The Basics

Hello! Gonna detract from my Doppelganger posts to provide a quick tutorial for a friend who wants to learn Ren’py. I won’t be going into detail, because this is for someone who has never done CS.

Setting up the Game

First, create a new project in Ren’py once you have everything set up. Follow the instructions to install Editra, which is theĀ  most user-friendly IDE that Ren’py offers automatically. Setting the game directory is very important as well, because it will allow you to add images to the game. To change where Ren’Py creates game directories, click “preferences” button at the bottom right of the Ren’py screen .

8p1cmed

Once you’re done setting up the directory, go back to the main Ren’py screen and create a new project. There’s no button to confirm the name, just click “Enter” and follow the other self-explanatory instructions.

On the main Ren’Py screen, open up the file labelled “options.rpy”. This is the file that will, un-surprisingly, edit the options of the game, such as the resolution, which is what we’re interested in right now.

The default resolution is 800×600, which is pretty low to me. I’ve changed it to 1280×720, but it can pretty much be whatever. Just remember it for backgrounds and stuff.tsnme1f

Alright! Now, it’s time to pull out your drawing tablet (or your mouse, you know, whatever floats your boat) and get some basic art done. For this example, I’ll be using art from Doppelganger, which already fits the screen resolution. You can download the basic background and characters here to play with.

Classroom, Locker

Holly Sprites (Angry, normal, sad), Tristan Sprites (Normal, Angry)

Make sure that you copy and paste ALL of these images into the game folder. This should be in directory of where you created the project. I like to organize my images into folders in the game directory. Note that I didn’t put the image folders into the folder labelled ‘images’, which will play a role in how I find my images in the code later.

4l1cidu

Now, you have to initialize all these variables in the script. Open up “script.rpy”. Define your characters for easy access later. You don’t have to, but it sure as hell is easier than writing it out each time. Use a hexadecimal color picker for the character’s color. This is the color that will show up as the player’s name.

# Declare characters used by this game.
define rachel = Character('Rachel', color="#ff69b4")
define senpai = Character('Senpai', color="#ffffff")

Note that in Python, “#” is used to comment out lines. This means that the line does not affect the code in any way and is there as a “comment”.

Now it’s time to initialize the different expressions and states of the characters. You declare an image variable by using this format:

image character expression = Image("image directory")

for example:

image holly normal = Image("characters\holly_normal.png")

Note that because I put the images into folders, I need to tell the game which folder it is in. The game automatically looks at the “game” folder as the directory, in which two more folders called “characters” and “backgrounds” are in. Finish that for all the character states and your script should be looking something like this.

spmzknm

 

 

Now, initialize the backgrounds using the same format. The final initialization of all variables should be done.

ibr2bcu

You are now ready to code!

Basic Script and Menu Functions

Great, you have some variables. Now it’s time to do stuff with them. Ren’py should’ve already made a label (can be thought of as a method) called start. For future reference, these labels can take in parameters just like a normal method, albeit it’s kind of different from other languages like Java. This “start” label is where the game will start (no, really??).

First, declare the background using

scene background with transition

Let’s start off in the classroom, with a nice fade. You can change the length of the transitions using code, but let’s not get into that for now.

scene classroom with fade

Now, let’s have “Rachel”, our main character, confess her love to “Senpai”. We can just use the characters that we so smartly declared in the first step to do this, and it should follow all the properties you’ve given it.

You can show the character images the same way. There are 3 basic positions: center, left, and right. You can initialize your own positions later as well, so don’t think Ren’Py is that nonversatile.

fnlmqys

Save the files, and click Launch Project. You should have a cute little confession scene going on.

nz2faw9

Now, let’s give Rachel some choices on how to confess her love using a menu. Let’s go ahead and give our game a “good’ and a “bad” ending, so we have to give it some type of conditional. Let’s make a “lovepoint” system in which different choices will affect your score.

vzrm3ag

 

Use the “$” key to declare a Python variable. Python is dynamic type unlike Java, so you don’t have to specify what type of data it is. Notice how I specified Rachel to start a sentence, and for the user to finish it. Their decision affects their ending.

Now, we would need to make these endings using new labels (once again, think of them as methods). Let’s have a “goodending” and a “badending” label.

jb0cprt

Now that you have the labels, you have to put stuff into them, obviously. Let’s have the couple move to the lockers for more privacy.

8gxnnyh

Alright! We have our endings. Now, how do we access them? Let’s jump back to the start label and use the lovepoints as a conditional if statement.

ju5c9ak

Notice how I had Senpai respond to Rachel, because it would be awkward to just move scenes. Make sure that once you’re done writing the menu, you tab back to the correct indentation or it will show up in the menu instead of the main script.

“jump” is a very important function, and it does exactly what you think it does: it causes the game to go to that label.

Anyways, this tutorial should be enough to cover a basic linear game! I’ll make another one on screens and buttons later.

**Something I forgot to mention! You can just change expressions of the character without re-specifying their location. For example:

show senpai normal at right with dissolve
senpai "How could you do this to me Rachel?"
show senpai angry

Dev Blog #5

7/2/2016


Parameters

if(hollylocker == "092114" or hollylocker == "92114"):
Ā Ā Ā Ā Ā Ā Ā  call openlocker("True") #ignoring other parts of the code for now
label openlocker(firstTime = False):
Ā Ā Ā  scene hallway
Ā Ā Ā  if(firstTime):
Ā Ā Ā Ā Ā Ā Ā  "You open Holly's locker."
Ā Ā Ā Ā Ā Ā Ā  player "Oh, I found a map. I'll hang on to this for now."
Ā Ā Ā Ā Ā Ā Ā  player "I should check out the locker first."
Ā Ā Ā  show screen mapbutton
Ā Ā Ā  scene locker
Ā Ā Ā  call screen locker

Parameters are different in Python than I’ve noticed in every other language I’ve used and it’s really quite odd. The call to the label requires me to put in a default value for the parameter, which I have never seen before. I think this acts as a safety net as it decreases the possibility of a run-time error because the parameter always has a given value. Anyways, if it’s the first time the player opens the locker, it will give the player a map that shows up in the top right of their screen that they can then use to teleport throughout the school!


Map/Locker Code

I’m really tired from getting my wisdom teeth out so this may be kinda loopy.

screen map_screen:
Ā Ā Ā  add "map/bg.png"
Ā Ā Ā  add "map/map.png"
Ā Ā Ā  textbutton _ ("Exit") xalign 0.002 yalign 0.055 action Hide("map_screen", transition=Dissolve(0.25))
Ā Ā Ā  #also for the other locations, but only showing one for now
Ā Ā Ā  imagebutton idle "map/lockers_base.png" hover "map/lockers.png" focus_mask True action [Hide("map_screen"), Jump("openlocker")]
Ā Ā  Ā 
screen mapbutton:
Ā Ā Ā  textbutton "Show Map" action Show("map_screen", transition=Dissolve(0.25)) align (.95,.04)
Ā Ā  Ā 
screen locker:
#only showing one object
Ā Ā Ā  imagebutton idle "locker/l_books.png" hover "locker/l_books_hover.png" focus_mask True action NullAction() 

I actually had some of trouble with this code. The buttons aren’t implemented yet so the player can’t really explore the locker. Well, I didn’t realize that for the action list, Jump had to be the last action.

action [Hide("map_screen"), Jump("openlocker")]

I put Jump first and couldn’t understand why it wasn’t hiding the map screen when I chose my destination to teleport to, until I realized that the game would jump there first and never reach the second statement and Hide the map.

Anyways, here is everything in action:

 

Dev Blog #4

6/27/16 – 6/28/16


Phone Puzzle

I finally got the phone puzzle to work! I have no idea why, but it does. When I tried using a String to store the currently inputted numbers through an action from the imagebutton, I didn’t put parenthesis around the variable name that held the password, which caused it to break (I’M NOT USED TO PYTHON OK).

However, I figured out that the action AddToSet() causes the button to become deactivated afterwards, while SetScreenVariable does not. Why? I may never know. The final code ended up being super simple:

screen phone:
Ā Ā Ā  default code = ""
Ā Ā Ā  imagebutton idle"phone/1_base.png" hover"phone/1_hover.png" focus_mask True action SetScreenVariable("code", code + "1")
Ā Ā Ā  imagebutton idle"phone/2_base.png" hover"phone/2_hover.png" focus_mask True action SetScreenVariable("code", code + "2")
Ā Ā   #continue for buttons 3-9
Ā Ā Ā  imagebutton idle"phone/confirm.png"focus_mask True action If(code == "1234", Jump("openphone"), Jump("fail"))

I also implemented a text message system where the player can view Holly’s texts through a series of screens. Once the player unlocks the phone, the script calls a screen that will then allow the player to select who to read messages from. I made 5 buttons to represent five different conversations, and upon selecting a button, it jumps to the specified label in the script. Here’s it in action (disregard bad art for now):

The script was super redundant to write, and I know there’s better ways (such as creating a class, etc), but I’m still too new to Python to dare to attempt that.

screen select:
Ā Ā Ā  imagebutton idle"phone/dad_base.png" hover"phone/dad_hover.png" focus_mask True action Jump("dadphone") 
#continue for other conversations


#phones
label dadphone:
Ā Ā Ā  show phone dadphone
Ā Ā Ā  pause
Ā Ā Ā  jump plsnomore

label plsnomore:
Ā Ā Ā  show phone messages
Ā Ā Ā  call screen select

I added a “plsnomore” label because it added at least a LITTLE BIT of efficiency to this terribly inefficient code. For a first game, I think it’s pretty aight.

I’ve been spending a lot of time playing Black Desert Online and it’s been distracting me a lot from trying to develop this game. WHY CODE WHEN YOU CAN TAME WILD HORSES AM I RIGHT??

Later, I realized that even I didn’t need a confirm button as shown in the video. I found out here the code will only check after being called through an action or a python block. Instead of a confirm button, I added it as a conditional to the number buttons themselves to check the passcode if it were 4 digits long.

I added another action statement, but then quickly came to the realization that an imagebutton will only perform the first action so I couldn’t do that. I ended up doing something super awkward by combining everything into one action statement.

#action for the other numbers
action If(len(code) < 3,SetScreenVariable("code", code + "5"), If(len(code) == 3, Jump("fail")))

#action for the correct ending number
action If(len(code) < 3,SetScreenVariable("code", code + "6"), If(len(code) == 3, If(code == "641", Jump("openphone"), Jump("fail"))))

First, I check if the previous 3 numbers are correct for the ending digit. The passcode is “6416”, so when the player presses “6”, it will check if the length of the passcode String is 3 digits long, and if it is, it will then check if they are the correct 3 digits. I also added the code for 5 to show that if the player enters 4 wrong buttons, the code jumps to the “fail” screen.

 

Dev Blog #3

6/24/16


Phone Puzzle

Now that I’ve gotten some progress on the art down, I want to go ahead and figure out how to code in the puzzles with Ren’Py. I’ll start with the phone! No spoilers on how to get the passcode, but once the player obtains it, I want them to be able to press buttons on the super great looking phone I drew to get in.

I ended up taking an hour figuring out how to even add a button (I’m really smart I promise).

MyĀ  main issue was not realizing that Ren’Py will only show imagebuttons on a screen, and you then have to call the screen on the script. I finally got the button to show up by editing the screen.rpy and adding a test button with the script:

screen phone():
Ā Ā Ā  imagebutton idle"phone/1_base.png" hover"phone/1_hover.png" focus_mask True action Quit(confirm=False)

and then calling the screen from the script.rpy. @_@ I’m so tilted right now holy crap.

Anyways, figuring out how to make clicking buttons append a currently entered passcode is the hardest part. I couldn’t get it to append to a String, nor a list when clicked.

I tried doing this (among a bunch of other variants):

screen phone():
Ā Ā Ā  $ passe = []
Ā Ā Ā  imagebutton idle"phone/1_base.png" hover"phone/1_hover.png" focus_mask True action AddToSet(passe, "1") #button1
Ā Ā Ā  imagebutton idle"phone/2_base.png" hover"phone/2_hover.png" focus_mask True action AddToSet(passe, "2") #button2
    #continue 3-9
    #testing to see if passe is appended
    if len(passe) > 0:
        action Jump("scene2")

However, I would never be able to get the scene to jump. I ended up figuring out that the engine doesn’t work like I’m used to in Java (not like a step function) and it won’t call the if statement that checks the password UNLESS it is in a Python statement or if it is explicitly called by something else. I made a “confirm” button to call the Jump action, because if I made it into a Python block I wouldn’t be able to make imagebuttons and call actions like I have been doing.

screen phone():
Ā Ā Ā  default passcode = []
Ā Ā Ā  default code = ""
Ā Ā Ā  imagebutton idle"phone/1_base.png" hover"phone/1_hover.png" focus_mask True action AddToSet(passcode, "1")
Ā Ā Ā  #repeat for buttons 2-9
Ā Ā Ā  python:
Ā Ā Ā Ā Ā Ā Ā  if len(passcode) == 4:
Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā  for item in passcode:
Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā Ā  code += str(item)
Ā Ā Ā  imagebutton idle"phone/confirm.png"focus_mask True action If(code == "1234", Jump("scene2"))

I had to call a python block to convert the list to a String because the “Confirm” imagebutton wouldn’t compile when checking a list. I also couldn’t append a String in the first place, which is why it’s a list. I also had to check the length of the list, or it would give me a compile error for trying to add items from an empty list. Here’s what the test screen looks like:

ss+(2016-06-24+at+05.32.15)

Obviously the art needs work, but I’m working on the code for now. The phone DOES unlock with the proper set passcode now, but I’ve run into another issue. Once a button is pressed, it becomes inactive and it won’t let you press it again or even show the hover state, which bothers me a lot. There’s no reset function, so I’m currently thinking of doing something really arbitrary like reloading the entire screen after a single button is pressed.

It doesn’t affect the gameplay too much as long as I make the passcode 4 different numbers (such as 1234), but I can’t make one that’s like 1111. I’ll try figuring that out tomorrow.

Dev Blog #2

6/23/16


Positions

Another day working on the basics of Doppelganger before I can start doing some heavy scripting! I went ahead and initialized some basic positions to use (based on coordinates) so I wouldn’t have to type them out each time. There’s already default left, right, and center, but here are a few other positions.

init:Ā  
 #Positions
Ā Ā Ā  $ slightleft = Position(xpos=0.2, xanchor='left')
Ā Ā Ā  $ slightright = Position(xpos = 0.7, xanchor = 'right')

It took me a while to realize that the position is relative to the upper-left corner of the screen (and that’s why you properly read documentation, folks).


IDE (Editra) Issues

A really weird issue is one with the IDE I’ve been using for Ren’Py (Editra). It’s scaling really awkwardly on my computer when I run it in conjunction with Ren’Py, but it runs fine alone. Normally disabling DPI-Scaling on the properties of the executable fixes it, but it didn’t do anything this time. Not sure if you can quite tell, but if you zoom in you can see how blurry the IDE text is and it really bothers me.


Tristan Sprites Progress

It’s time to revamp Tristan’s sprites! The concept art was ok, but I think he needs to look a lot more masculine and cool as the “bad boy” archetype. I hope I can make a route for his life as well, because I’d like to think he’s not really the bad person he seems to be.

I started to re-sketch him while listening to some BTS, because I like getting into the mood when drawing these characters. He’s gotta be COOL. It was kind of funny because I was using a YouTube playlist out of laziness and when I paused the song I was on, I realized the pose was nearly the same as the one I was drawing.

ss+(2016-06-23+at+01.43.20)

Anyways, I’m actually not happy with the final sprite at ALL. I think it’s nowhere near as good looking as it should be and I’ll most likely revisit it again later. It just looks so…flat. My coloring was really off here and it seems really desaturated.

Here’s the comparison between Tristan’s original concept art (right) and his sprite. Ignore the size difference since the original was off!


Game Previews

Finally, I got to test some of this art out on the game. It’s looking pretty good! Tristan’s art is still bothering me, especially moreso in game. I’ll have to look into fixing him up later.

Dev Blog #1

6/22/16 (It says 23, but it’s like 2AM)


Welcome

Welcome to Doppelganger’s dev blog!

A quick warning that this blog will be pretty personal, but I hope anyone reading this is as entertained by my journey as I am.

I started off this visual novel project a couple months ago for high school, but never really had the time to put much into it. I wanted it to be a game that puts the player in someone else’s shoes — literally, and shows them that life isn’t all the it seems to be.

I’m using Ren’Py, and I haven’t used Python since the Middle Ages. Thankfully, writing the script in Ren’Py isn’t terribly difficult and I’m pretty sure someone with minimal coding experience could do it once they get the initialization of character variables down.


Holly Sprites/Design

I spent some time in SAI today reworking Holly’s sprite image. Holly’s supposed to be the stuck up brat of the visual novel, but she actually turned out to be favorite character when I first thought of this idea. She’s named after a good friend from middle school of mine who is probably the polar opposite of her. Here’s Holly post plastic surgery with her old design on the right:

I decided to go for a softer look to the VN instead of the rougher style I did earlier. I hadn’t tried making the line art the same color as the object before, but it really does look better (aka the line art isn’t straight black but matches a darker tone of the skin/dress/whatever).

Here’s all of her expressions (normal/angry/sad).


Main Screen

I’ll be reworking Tristan (her slightly of a jerk boyfriend) next, and likely the start screen of the game because no one can tell that Holly’s looking at her reflection through a window.

Man, what do I have to do to show she’s indoors?

coverscreen