I am an idiot, Please Help Me Learn Ren'Py.

Hello all!

I wanted to make a thread where I just… lay out my shortcomings and ask for help from the community. There are so many talented game devs here, especially a large number making Visual Novels through programs like Ren’Py.

I am not an experienced coder. I’m a computer idiot. I can make basic choices and dialogue through scripting, but I’m really struggling to grasp more advanced concepts, like increasing stats and triggering events.

If any of the developers working on or who have worked on visual novels and the like through programs like Ren’Py want to talk about their experience and help a rookie survive Python… I’d appreciate it.

Right now, I’ve been playing with a very early demo for an ongoing project, a small engine I downloaded for making Dating Sim daily choices, and occasionally digging into the (far too advanced for my monkey brain) files for Tramp and Fill Me Up.

Thanks again for your help, anyone who stumbles upon this

5 Likes

I haven’t posted any games or anything here yet, but I’ve been looking into ren’py a bit as well
Actually very happy you made this post, cuz I really believe in helping eachother out with things like this

Python, luckily, isn’t the most difficult language to learn and work with, Ren’py also allows creators to do quite a bit of work without too much complex coding
I’d love to go back and forth with you and see where things hit roadblocks, we can just chat a bit on that as well

If I have any general advice: don’t worry too much about how your code looks for now, and keep your first projects fairly small. Just try to understand what is happening, and why the code does the things it does.

Also, depending on how ‘beginner’ you are, do look up some basic videos about python (just basic python, not ren’py) and do some research on variables, if-else statements and loops
If you understand those 3 you should be able to puzzle yourself through a LOT

Now, my message may look like a mess, my 3 AM monkey brain has been awake for a bit longer than it should be, but breathe in, breathe out, you got this, make a plan and we’ll wrestle our way through

5 Likes

Hey thanks! I really appreciate the response and would love to talk with you about the profess

Think the best place to start is understanding that renpy is programmed in python and for the most part renpy script is just a simplification/extension of python. For the most part you can actually write your entire game in either renpy script or python, or a combination, and it would not matter much. While knowing python would be extremely helpful for an advanced game or or one that intends to get away from a visual novel. For the most part, to make a basic games knowing python is probably unnecessary to make a visual novel or game.

While i did know how to code before i made my first renpy game, i did not know python and actually just learned renpy script by the included demo/tutorial in the sdk. They even include a tutorial on making pong in the renpy visual novel engine, to demonstrate that while the script was built for visual novels, sky’s the limit if you know some python and get creative. Also by reading the fairly complete documentation for renpy script on the renpy.org page.

Renpy script uses if then else statements along with labels for flow control. along with direct python variables for all tracked variables. If you can make a flow diagram for your story or game, with decision branching, then each block between the decision points is a label, and you just have your variables you track stats or decisions with that you use in the if then statements to decide which label to execute next.

In summary i would start with the demo/tutorial in the sdk, with the renpy.org page used to find lots of the nitty gritty details needed as you get more advanced. Also would read this Some notes about RenPy by @dingotush who has some helpfull pointers on quirks of renpy

3 Likes

Something like atom is a must for deciphering projects with lots of rpy files rather than one single script.rpy file.

otherwise ren’py are almost all:
if statement
menu
declare variables as 0 at start
variables +1
dialogue commands that alter who is speaking and font
show to show images
jump and return to make labels: work

So, uh, which of the above commands do you not understand? I’ll try to address them in more detail.

So like trying to understand tramp is like impossible with a text editor like atom, or other coding based text editor.

One thing though, I think debug text is useful, and I mod most games I play so that some dialog that comes up often like a daily hub menu or some such I just add like variable [variable] variable2 [variable2] to the text.

I also like to add those right after random choices are made, which helps me find typos and bugs in games, where I’ve posted bugs and bugfix suggestions before.

For example tiggertoo’s weightgaming had a debug section that displayed at all times and was cut down by some # comment flags and editing that area helped me hunt down bugs.

3 Likes

Expanding on the comment about using a proper code/text editor like Atom, I use Visual Studio Code as my text editor and it has a plugin that actually highlights ren’py’s syntax which makes it much easier to keep track of the things you’re typing and whether you’ve missed something simple like a quotation mark.

4 Likes

Yeah atom has a similar plugin although atom is now dead as of today I believe (they’re no longer working on it at all), so it might be harder to obtain? (but since it’s already installed on my machine I’m gonna keep using it until I get an issue, then I’ll consider moving to new tech.)

2 Likes

I know I’m late to this party, but if you want to know how Tramp works, or specific bits, I can definitely answer those questions. Some of the detailed code is complex, I know, but that wouldn’t stop you re-using bits for your own game.

2 Likes

Thank you for this offer! I’d be very interested. I cannot figure out how to track variables and create a cyclical day system.

What are you looking for? Do you want to tracks days and hours, or days and periods (such as morning, lunchtime, afternoon, evebning, night)?

1 Like

Days and periods would be preferable, with events you can do during each timeblock

Another example of this you can reference, is in my game Project Bob.

1 Like

thank you, I will definetly look into your game as well, I just am struggling to get variable tracking and timeblocks down

Sorry for the delay, a bit busy. I’d probably start with something like this:

datePeriod.rpy:

#
# Date/Period.
#

    # Name the days of the week.
    # Could be added to if you want an eight day week for example.
    #
define  daysOfWeek = [
        "Monday",       # 0
        "Tuesday",      # 1
        "Wednesday",    # 2
        "Thusday",      # 3
        "Friday",       # 4
        "Saturday",     # 5
        "Sunday",       # 6
    ]

    # Name the periods of a day.
    # Can be added to or shortened as needed.
    #
define  periodsOfDay = [
        "Morning",      # 0
        "Lunchtime",    # 1
        "Afternoon",    # 2
        "Evening",      # 3
        "Night",        # 4
    ]

default day = 1             # Day number
default dayOfWeek = 0       # Day of week
default period = 0          # Period of day

default dayOfWeekStr = daysOfWeek[dayOfWeek]    # Current day of week string
default periodStr = periodsOfDay[period]       # Current period string

init python:

        # Advance a number of periods.
        # Updates periodStr and dayOfWeekStr too.
        #
        # delta   - Number of periods to advance (default 1)
        # rollDay - True (default) to advance to the next day,
        #           False to stop at last period of current day
        #
        # NOTE: delta can be negative if you need to travel backwards in time.
        #
    def addPeriod(delta = 1, rollDay=True):
        global period, day, dayOfWeek, periodStr, dayOfWeekStr
        periods = len(periodsOfDay)
        period += delta
        if rollDay:
            # Use mod math to advance period, day, dayOfWeek.
            day += period // periods
            dayOfWeek += period // periods
            period %= periods
            dayOfWeek %= len(daysOfWeek)
            dayOfWeekStr = daysOfWeek[dayOfWeek]
        else:
            if period >= periods:
                period = periods - 1
            elif period < 0:
                period = 0
        periodStr = periodsOfDay[period]



        # Advance to the start of the next day.
        # Updates periodStr and dayOfWeekStr too.
        #
        # delta - Number of days to advance (default 1)
        #
        # NOTE: delta can be negative if you need to travel backwards in time.
        #
    def nextDay(delta = 1):
        global period, day, dayOfWeek, periodStr, dayOfWeekStr
        period = 0
        day += delta
        dayOfWeek += delta
        dayOfWeek %= len(daysOfWeek)
        dayOfWeekStr = daysOfWeek[dayOfWeek]
        periodStr = periodsOfDay[period]



    # Simple screen top right to show day, day of week (first three letters), and period.
    # Should probably move this to a separate file.
    #
screen simpleDateTime():
    frame:
        xalign 1.0
        yalign 0.0
        text "Day [day] [dayOfWeekStr:.3s] [periodStr]"

A simple script to test it:
script.rpy

define pc = Character("You")


label start:
    show screen simpleDateTime
    pc "Urrgh, Mondays. Who needs them?"

    "You stay in bed, feeling ill."
    $ addPeriod()

    "You manage to eat a little chicken soup, take an aspirin, and go back to bed."
    $ addPeriod(2)

    "You wake and check your socials, but it is all too much, and you let sleep take you again."
    $ addPeriod(3)

    "Wait ... It's lunchtime? How long did I sleep?"
    "No ... this can't be happening. Am I having a lucid dream?"
    $ addPeriod(-6)
    "Your alarm goes off, time to get ready for work."

    "End."
    return
1 Like

Ok so i thought i would add some explanation to @dingotush code that may be helpful. Starting with python and by extension renpy script syntax is mostly white space dependent, and indentation means everything!

define in the renpy script tells the renpy game engine to crate a variable(since its a python engine your really just making a python variable). Python variables are sort of polymorphic, but for the sake of keeping things simple, daysofWeek would be a list and dayOfWeek would be an integer to start.

Ok so i feel like next in the script @dingotush sort of jumped right into the deep end (although its probably the correct way of doing it) @dingotush uses init python: which in renpy script tells the renpy engine that the following indented block is pure python code(note that everything in a python code bock is treated as one line in the renpy script). He then in python inside the code block defines some python functions with default variable inputs(again a slightly advanced move using default variable imputs for a beginner at python).

Ok last thing thing happening back in renpy script outside the init python: is defining a screen in renpy script. using screen yourscreennaemhere(): tells the script the next script block is all for that screen. You can pass variables to the screen inside the () like in a function. and like a function a screen can return something. Getting more advanced a screen is a python class predefined by the renpy engine, and what your actually mainly defining other than the name in the renpy script is the render function of the screen class object. Why this is important to know is renpy pre renders screens. No literally the engine will actually call the render function ahead of time for your screen that way when its time to show that screen it will be done rendering. If you change the value of a variable in the script block for the screen it changes whenever the render function is called, which can be before its displayed to the player. In other words adding a line $ day += 1 to the simpleDateTime screen would make it add 1 to day every time it prerendered or rerendered the screen making your day counter count way to many times and posibly mess with other uses of that variable the player may be interacting with(try addin the above to the screen in his demo code and try it out to see what i mean). If you want a screen to modify variables in your game for instance a button to click to increase a stat you have to do this via screen actions.

So in the script.rpy, again in renpy script were again using define to define another python variable, this time one of renpys custom predefined python classes, a Character which is very useful for making writing in the script easier. Then we define a renpy script label. ( Python does not natively have labels, and uses a library to implement them in python, to be able to use them in the script, i forgot which library its using). Labels in renpy script is just a way of breaking your script up into chunks that you could then call, or jump to. The operate much like a function with some extended abilities, and can have passed variables and return things just like python functions also you dont have to return at the end of a label you can just flow into what ever follows it in the file. Then we proceed to use these newly defined variables and functions to track time, with the day ,dayOfWeek, and period variables which are just integers manipulated by the functions. Hes doing this by using the $ which in renpy script denotes a single line of python code to run. Here we are just calling the functions defined in the other file.

All together were using an integer to track the various time variables because when we put the integer into the key input of a list such as daysOfWeek[yourkeyhere] we can get back the text of what the time period or day it is. We use functions to change our interger variables to make sure we don’t miss manage the time variables, such as going past days end the periods variable accidentally because we forgot to manually check if we matched or exceeded it.

So just for example i modified @dingotush work to show as pure renpy script example as you can get, using script labels instead of python functions. Also being lazy i mashed it into one file:

define  daysOfWeek = [
        "Monday",       # 0
        "Tuesday",      # 1
        "Wednesday",    # 2
        "Thusday",      # 3
        "Friday",       # 4
        "Saturday",     # 5
        "Sunday",       # 6
    ]

define  periodsOfDay = [
        "Morning",      # 0
        "Lunchtime",    # 1
        "Afternoon",    # 2
        "Evening",      # 3
        "Night",        # 4
    ]

default day = 1             # Day number
default dayOfWeek = 0       # Day of week
default period = 0          # Period of day

default dayOfWeekStr = daysOfWeek[dayOfWeek]    # Current day of week string
default periodStr = periodsOfDay[period]       # Current period string

label addPeriod(delta = 1, rollDay=True):
    $ periods = len(periodsOfDay)
    $ period += delta
    if rollDay:
        $ day += period // periods
        $ dayOfWeek += period // periods
        $ period %= periods
        $ dayOfWeek %= len(daysOfWeek)
        $ dayOfWeekStr = daysOfWeek[dayOfWeek]
    else:
        if period >= periods:
            $ period = periods - 1
        elif period < 0:
            $ period = 0
    $ periodStr = periodsOfDay[period]
    return

label nextDay(delta = 1):
    $ period = 0
    $ day += delta
    $ dayOfWeek += delta
    $ dayOfWeek %= len(daysOfWeek)
    $ dayOfWeekStr = daysOfWeek[dayOfWeek]
    $ periodStr = periodsOfDay[period]
    return

screen simpleDateTime():
    frame:
        xalign 1.0
        yalign 0.0
        text "Day [day] [dayOfWeekStr:.3s] [periodStr]"

define pc = Character("You")

label start:
    show screen simpleDateTime

    pc "Urrgh, Mondays. Who needs them?"

    "You stay in bed, feeling ill."
    call addPeriod()

    "You manage to eat a little chicken soup, take an aspirin, and go back to bed."
    call addPeriod(2)

    "You wake and check your socials, but it is all too much, and you let sleep take you again."
    call addPeriod(3)

    "Wait ... It's lunchtime? How long did I sleep?"
    "No ... this can't be happening. Am I having a lucid dream?"
    call addPeriod(-6)
    "Your alarm goes off, time to get ready for work."

    "End."
    return

If you looked at my Project Bob you can see a similar but different setup working. You can open the scripts.rpa in a text editor and search for these variables.

game_days -----> main day tracking integer
day_step ------> same as @dingotush period integer
next_day_step ------> really its an integer that is 1 greater than day_step
day_periods -------> list of day periods

p_navigation is the screen that displays the current day at the start of the day, also has the button for starting the day jumping us to the first label. search for the label start_day to follow the main game loop. for every period of the day we jump to label travel where we go to the location of the action taken and incerment the day_step, then go to the label for that action, at the end of the acition we jump back to travel, if the day_step has reached 6 the end of day we jump to p_day_end to end the day and go back to label main and bring back all the navigation. note that main is a never ending loop bring back the p_navigation between goigng to other screens until a player quits or uses the p_navigation screens start day button to jump to start_day label

1 Like

I could be doing this completely wrong, but I’m not sure what I’m doing wrong. This is a WIP relatively simple game, mostly used to teach myself variables. I’m failing at the variables part.

How do I make it not have syntax errors, and how do I make things change depending on the increase or lack thereof of the variable?

# The script of the game goes in this file.

# Declare characters used by this game. The color argument colorizes the
# name of the character.

define s = Character("Sophie")

#Kayla is a bottom-heavy blonde with secret feedee and lesbian preferences

define a = Character("Anna")

#Anna is a busty and fit girl with long dyed-red hair.

default $ sophiefatness = 0

init python:
    def tick(amount=1):
        global time, time_map
        
        time += amount
        if time > len(time_map):
            time %= time_map

default time = 0

define time_map = [
    "morning",
    "day",
    "noon",
    "afternoon",
    "evening",
    "night",
    "latenight"
]

# The game starts here.

label start:

s "My first day on-campus. You can do this, Sophie. It's just college, almost everybody has done it."

s "I've just gotta study hard, make some friends-"

s "-and avoid that freshman 15 my mom kept warning me about..."

"My cheeks start to turn red, warmth rushing to my face."

s "Why am I blushing over that? W-whatever..."

s "Made it to the apartment I found online. That ad really came in just when I needed it most!" 

s "A place this big would be a lot more expensive usually, but there's another roommate here to split the rent with!"

s "I wonder what my roommates will be like?"

s "Time to find out, I guess."

scene dormroomempty

s "Hello? Anybody home?"

a "Yes? Who are you?"

s "Oh! I'm Sophie!"

"The girl stares at me blankly for a moment."

s "I'm uh... your new roommate!"

a "Ohh! You're the one who responded to my ad on Greg's List!"

a "You know, before you came along, I wasn't sure anyone was gonna respond to that ad."

a "I almost forgot about it and planned on posting ads locally instead."

s "W-well I'm glad you didn't! I uh, really needed this place."

"Now that the introductions were done, I took a moment to look at my new roommate for the first time."

"Anna was gorgeous. Seriously, she could be a model! Those beautiful crimson locks, those piercing green eyes, that flawless skin..."

"AND THOSE HUGE TITS! LOOK AT THE SIZE OF THOSE THINGS!"

a "Earth to Sophie? Hello?"

s "Huh? S-sorry I'm here! What did you say, again?"

a "I asked if it was okay to go over a few house rules with you. But if you're so distracted by something right now..."

s "N-no I'm fine! I promise!"

a "Then good. Alright, well, each day, feel free to do whatever you want around here."

a "Though I recommend eating meals and going to class, obviously."

a "If you ever want to hangout or anything like that, just let me know!" 

a "Though, I really like my beauty sleep, so I won't be down to hangout in the early morning or late at night."

a "Some things just aren't doable at different times, ya know?"

s "R-right, I guess."

a "With that tutorial, I mean explanation, out of the way, why don't we get something to eat?"

s "Huh?"

a "It's already noon! Surely you need to stop and get some lunch, you've been busy all-day moving!"

s "W-well, maybe..."

"Admittedly, I had already had a decent enough lunch just an hour or two before. I made a sandwich or two back at my parent's place."

"But I wasn't sure if I wanted to pass up an opportunity to get to know my new roommate on the first day, before classes even started!"

menu:
    a "So, yes or no on the lunch break?"
    "Sounds good to me!":
        jump firstbinge

    "I kinda wanna get setlled in right now. Maybe another day?":
        jump dayonedeny


label firstbinge:
a "Awesome! You're gonna love this!"
"Anna jumped from where she was standing and rushed off to the kitchen, immediately pulling things out of the fridge."
a "I may be a Psychology major, but my REAL passion is cooking!"
s "Oh wow!"
"My mouth began to water a bit as I smelled the distinct scent of cooking meat."
s "Whatcha makin'?"
a "Burgers! I had some frozen ones lying around, and I can make 'em extra special!"
s "Looking forward to it!"
"I waited for around 10-15 minutes while Anna cooked."
a "I hope you're hungry!"
"Anna reappeared with a platter of burger patties stacked high, about 7 of them."
s "This is... a lot of food, Anna!"
a "Sorry, I'm awful at cooking smaller portions of food..."
a "Anything we don't finish is leftovers, okay?"
s "Alright..."
"And so we got to talking a bit. I learned she was a psychology major and culinary arts minor."
"I learned her family owned this property, so she got to live here for basically free."
"I told her that I came here to study art and communications."
"She was a sophomore, I was a freshman."
"And so we kept talking and eating, splitting the tray of burgers..." 
"I say 'Splitting' but in reality she only ate two of them. The other five... my bad."
s "Getting... full... ugh."
a "Sorry about that, Sophie."
a "I maybe went overboard for today."
s "It's okay."
a "Just relax a bit and let that digest okay? Won't do you any good to get an upset tummy on the first day here."
s "Fair point..."
"Anna got up and cleaned the whole mess up, before giving me one last look and smiling."
a "I think you and I are gonna get along perfectly, Sophie."
"For some reason, this sent a chill up my spine."
$ sophiefatness += 1
jump daily_choice


label dayonedeny: 
a "Oh uh, okay! Fair enough."
a "Feel free to hit me up to hangout, okay?"
"I felt a little bad ditching her, but I'd already eaten lunch."
"Time to start my first day!"
jump daily_choice

  #Example menu#

label daily_choice:

a "Did it work?"
"I hope so..."
s "Let's find out!"
a "START THE TEST!"

if $ sophiefatness = 1:
    A "Oh my god it worked!"

if else:
    s "Awww nuts."

"This game sucks."

    # This ends the game.
return

also, what code do I need to add to this to say “it is now afternoon” before they jump to “daily choice”?

This:

default $ sophiefatness = 0

should be just

default sophiefatness = 0

You only need $ when writing a line of Python. The default is a RenPy script feature.

Similarly:

if $ sophiefatness = 1:
    A "Oh my god it worked!"

should be:

if sophiefatness == 1:
    a "Oh my god it worked!"

Again, no $. Use == for comparison (one = is for assignment). Be careful about case sensitivity a is your character, not A.

This:

time %= time_map

might not do what you expect, maybe it does due to Python being Python, but try:

time %= len(time_map)

Ok so what i think what your missing is formatting and keywords.

Keywords first, if is both a renpy script and python keyword, the game engine knows what follows is the condition that will be in python why we dont need the $. default would be another renpy script keyword same with define. $ is also a keyword for renpy script saying to execute the inline written bit of python generally you only should have one keyword per line.

Now formating : denotes a block of script to follow for renpy script and does the same for python. Both will complain about empty following blocks, pass is a keyword that solves having to have something in the block when you want nothing. when ever you have block it is one indentation level in from the statement with the : in it.

#example for code blocks and keywords
if a==b:
    "were having a dandy time"
    $ c +=1                    #need to incerment somthing also if a==b
    if c >= 5:                 #example of a nested code block you can keep nesting
        $ c = 0
        jump somelabel
    "you will see this if c was less than 5"
"you should see this as long we did not jump to somelabel"
if j != k:
    pass  #an example of using pass really should just rewrite to checking if j == k and not have to use
else:
    "j is equal to k"
    init python:
        o = j + k                            #were in python so we dont need $
        word = "Hello"                       #were in python so we dont need default
        for letter in word:
            narrator(letter, interact=True) #renpys python equivelent to "[letters]" 
            #will display each letter of word as it cycles through     
    "were finaly outside the pyhton code block"

label somelable:                              #note the : and everything in the bock for the label is indented to show its part of the label
    "Here is 'sample' label." 
    if c >10:
         "wow c is now greater than 10"

label sample(a="default"):
    "Here is 'sample2' label."
    "a = [a]"

So one more thing on this:

so both in renpy script and in python if, else, elif(else if) are all keywords you only need one of them so it should be

if sophiefatness == 1:
    A  "Oh my god it worked!"

else:
    s  "Awww nuts.

and just for an example of a chain of elif 's

if colorpicker == 0:
     "You picked red"
elif colorpicker == 1:
     "You picked green"
elif colorpicker == 2:
     "You picked blue"
elif colorpicker == 3:
     "You picked yellow"
elif colorpicker == 4:
     "You picked orange"
else:                                       # will do whats in else if colorpicker was not 0 --> 4
     "Invalid choice"

you can use [ ] inside of quotes to output variables so if you had a variable word = “red” and in code had “roses are [word]” the player would see “roses are red”, the gotcha here is lists and dictionaries cant have their individual values put in the brackets like [list[key]] where list[key] would give you red. so you have to store the value of list[key] temporarily in something else then put that temporary value in the [ ].

so ignoring the fact that you have not used your function tick to increment you time variable at all in your script when you wanna display the current time period all you would have to do is have

$ temp = time_map[ time ] # were derefferencing the list time_map with the integer time to get word for the time
"It is the [temp]"  # if time was equal to 3 the output here would be "It is the afternoon"

If you noticed in @dingotush example he sovled having to have the temp variable by making a permanet one and always updating it in his functions. look at periodStr in his example code its would be serving the same function as my temp here but its upated whenever we change the time through our function meaning there is no need for the oneliner. So to make life simpler you would need define a new variable then change your function tick() to updated it. then you could just use that variable where ever you want to say the time.

define timestr = "text"

init python:
    def tick(amount=1):
        global time, time_map
        
        time += amount
        if time > len(time_map):
            time %= len(time_map)     #we should be modding by the length of time_map
        timestr = time_map[time]      #line i added to tick to update the time string whenever we update the time with tick

now with those changes anywhere you want to say what the time is you just

"It is the [timestr]"  # if time was equal to 3 the output here would be "It is the afternoon"