Any Open Renpy Games I can learn from?

Fuku95

Newbie
Jul 27, 2023
55
23
I've played Ren'py games here and there. Since I'm interested in game development, does anyone know of any Renpy games that have their files open so I can learn from them? Having numerous ones with different play styles will help me out. Almost all the games I come across frome Renpy are encrypted.

So far I only came across one that wasn't. Summer with Brina. However I need more to learn from.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,291
Just a warning, learning from other games also imply that you'll possibly learn stupid things. There's (alas) still a lot of developer who have no idea about what they are doing, and write ugly broken code.

This mean that you should focus on learning the logic behind the mechanism you want to use, more than on learning the code to implement that logic.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,583
2,224
General rule of thumb:

Avoid learning from any game that starts with something that looks like:

Python:
init:
    $ myvariable1 = 0
    $ myvariable2 = 0
    $ myvariable3 = 0
    $ myvariable4 = 0
    $ li1_love = 0
    $ li1_hate = 0
    $ li1_corruption = 0
    $ li2_love = 0
    $ li2_hate = 0
    $ li2_corruption = 0
    $ li3_love = 0
    $ li3_hate = 0
    $ li3_corruption = 0

-or-

Python:
init python:
    myvariable1 = 0
    myvariable2 = 0
    myvariable3 = 0
    myvariable4 = 0
    li1_love = 0
    li1_hate = 0
    li1_corruption = 0
    li2_love = 0
    li2_hate = 0
    li2_corruption = 0
    li3_love = 0
    li3_hate = 0
    li3_corruption = 0

Look for games that would code it like:

Python:
default myvariable1 = 0
default myvariable2 = 0
default myvariable3 = 0
default myvariable4 = 0
default li1_love = 0
default li1_hate = 0
default li1_corruption = 0
default li2_love = 0
default li2_hate = 0
default li2_corruption = 0
default li3_love = 0
default li3_hate = 0
default li3_corruption = 0

It's a tiny thing, but to my mind it is a good way of spotting games written by those developers who just copy/paste code from some other game without really understanding WHY things are coded like they are.

As I understand it, default was added as a solution to developers who didn't really understand when variables would and wouldn't be included in the save files. Developers would "fix" something in an earlier release and break their entire game. It's one of the reasons why you'd see "This version is not compatible with saves from version x.y and older".

This thing is, by that point - there were a lot of big title games already out there, using the "old" style of coding variables. And because those games were successful (although not very well written in some cases), people would "borrow" code from them or at least try to use them to understand what they should be doing. It was the blind leading the blind.

Anyway, whilst default doesn't guarantee a well written or structured game, it does at least show someone understood one of the basics of writing RenPy code.
 

aereton

Digital Hedonist Games
Game Developer
Mar 9, 2018
435
859
The previous tips are very good, however maybe someone who already decompiled some RenPy projects would post some examples of passably well written games, as I doubt someone who wants to learn from established projects can differentiate between clean and messy code examples.

I'd do it but I haven't touched any strangers yet.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,291
Because it's a good idea

Avoid learning from any game that starts with something that looks like:

Python:
init:
    $ myvariable1 = 0
    $ myvariable2 = 0
    $ myvariable3 = 0
-or-

Python:
init python:
    myvariable1 = 0
    myvariable2 = 0
    myvariable3 = 0
Regarding variable declaration, this too is bad practice:

Python:
label whatever:
    $ myvariable1 = 0
    $ myvariable2 = 0
    $ myvariable3 = 0

And of course, there's this that is a really bad omen:
Python:
default MC = Character( "mc" )
Variables that are constants shouldn't be savable.


On the same topic there's still some who are doing that kind of error:
Python:
define mc = Character( "[mc]" )

label start:

    "What's name do you want to use"
    $ mc = input( "Your name" )

Should also be added the (still too frequent):
Python:
label whatever:
    show screen whatever
    pause
    jump whatever
And its variations (there's too many to present them all).
The dev want a blocking screen that will wait for the player input, but neither use the , nor the syntax, that are made for this.


The use of show imageName when all the CGs are full screen.
Not understanding the difference between and , while they are the basis of any Ren'Py game is a really bad omen.


Talking about bad omen, the use of without related is also a strong one.
It's perfectly possible, and totally legit, to have the return in another label:
Python:
label whatever:
    [...]
    call calledLabel

label calledLabel:
    [...]
    if someCondition:
        jump subCalled1
    else:
        jump subCalled2

label subCalled1:
    [...]
    return

label subCalled2:
    [...]
    return
But it must always be ended by a return.

Doing so show a strong misunderstanding of how the game flow works.


Also a bad omen are games that copy/paste a big part of their code because of a small variation, especially when it regard the CGs:
Python:
label whatever:
    menu:
        "what swimsuit should she wear ?"
        "The red one":
            jump beachRed
        "The green one":
            jump beachGreen

label beachRed:
    scene beach001red
    girl "Wow, it's beautiful here."
    [...]

label beachGreen:
    scene beach001green
    girl "Wow, it's beautiful here."
    [...]
Here it's more excusable, but it's also not really difficult to find information on how to avoid this. It's been years that people promote the right way, and there's many games displaying it, some being already more than 5 years old.


More subtle, and so alas harder to catch, screens that handle all the action and update themselves for a long period are also to avoid.
 
  • Red Heart
Reactions: 79flavors
Sep 16, 2019
491
1,935
I'm not a developer but if I may make a recommendation, check out Game Developer Training channel on YouTube, he has a Renpy Master Class series that should be helpful.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,291
I'm not a developer but if I may make a recommendation, check out Game Developer Training channel on YouTube, he has a Renpy Master Class series that should be helpful.
Okay...

I just took a look at . It's one month old, and the code is:
Python:
label start:
    [...]
    while playing:
        $ UIreturn = renpy.call_screen( "mainUI" )
        if UIreturn == "dead":
            return
        [...]
And just this is enough to tell me that this guy don't know shit about Ren'Py !

Would he had opened the official documentation, that is available online, but also come with Ren'Py SDK into the "doc" directory, he would have found the . And then, he would have read the two first lines:
"The call screen statement shows a screen, and then hides it again at the end of the current interaction. If the screen returns a value, then the value is placed in _return."
 

osanaiko

Engaged Member
Modder
Jul 4, 2017
2,302
3,969
I have to second the criticism of Game Developer Training Renpy videos. (I won't comment on any other of the vids as I have not watched them. Although the Gell-Mann Amnesia effect suggests they might also be sus.)

I recently watched "Let's Code 4" series. The only good thing I can say about it is that it resulted in a game that appeared to work. But the style of the development made me shake my head.

I don't want to sit through it again to find specific examples, but stuff like making up random lists of class properties without planning the game design was painful and doomed. The mishmash of actions and effects and costs and energy points would result in a awful game design that belongs in the Flash era. The swing between early episodes making detailed directory structures for separating concerns and then in later ones just throwing all sorts of unrelated code together into a single file. The constant random capitalization/underscores vs snake case - why would you not just be CONSISTENT and not have to always refer back to check how you spelled a variable!!

Thundorn's code would not have survived a code review from me without a lot of grumpy comments, and probably a note to his mentor.

Maybe I should cut some slack as there is no one else putting out similar "non beginner" renpy video content. But honestly, it's not a great example to learn from.
 

Count Morado

Conversation Conqueror
Respected User
Jan 21, 2022
7,200
13,481
Isn't there a Ren'Py Tutorial already on the Ren'Py site? Would that be a bad place for the person to actually learn from?
 

Boarborn

Newbie
Apr 11, 2022
85
85
this seems like the good old purist versus practical programming to me
with a c++ background, pythonists has always attacked me i'm not pythonic, which i don't care since my code works and i get paid

here the case of 'default' is a real lesson, i would certainly adopt that if i use renpy
the other ones look like renpy purism
 
  • Like
Reactions: Turning Tricks

Turning Tricks

Rendering Fantasies
Game Developer
Apr 9, 2022
1,007
2,108
Okay...

I just took a look at . It's one month old, and the code is:
Python:
label start:
    [...]
    while playing:
        $ UIreturn = renpy.call_screen( "mainUI" )
        if UIreturn == "dead":
            return
        [...]
And just this is enough to tell me that this guy don't know shit about Ren'Py !

Would he had opened the official documentation, that is available online, but also come with Ren'Py SDK into the "doc" directory, he would have found the . And then, he would have read the two first lines:
"The call screen statement shows a screen, and then hides it again at the end of the current interaction. If the screen returns a value, then the value is placed in _return."
Seems like a sour grapes comment to me, TBH.

Matt is very open about being self taught, so of course his path to a goal is not going to follow the "standard". And yet, in Ren'py... even with as little knowledge as I have taught myself so far ... it is obvious that there are usually several ways to achieve a result.

What's more important though, is that he is an excellent teacher. In fact, IIRC, teaching is one of his RL jobs. When I started this hobby, I struggled to follow all the hundreds of examples of code snippets and examples plastered all over the net. And then I found the original Thundorn videos and he made it seem so easy to follow. In a few hours watching those videos, I learned more than in several weeks of trying to follow Lemma forum posts or examples on F95 here... including most of your stuff sadly.

You know your shit... no one disputes that. But you are very hard to follow at times and also seemingly without a social filter. That fact that you put a comment about being grumpy in your profile byline seems to suggest you know this about yourself, so I doubt I am saying anything new. But just shitting on a successful YouTuber who has taught many people how to get into Ren'py because they didn't code something EXACTLY as you might have done it is... well... I think that's petty.

I've been an engineer for over 30 years now and I have never fallen into the whole left-brain, right-brain myth. I have to force myself to do proper math and follow strict logical processes, but when I do, I usually do very well. Stuff that other people just get is sometimes difficult for me, and yet I can take a phone number someone gave me, use it a couple of times and then recall it years later. I can also take a snag report from a pilot and immediately visualize the various systems that are involved and then be able to start a troubleshooting process. There's lots of technicians I work with who are better pure mechanics (what we call "wrenches") but I have honestly never met a person that can understand how systems interact as well as I do. I know that's boastful, but it is true nonetheless.

My point is everyone has different strengths and weaknesses. The ability to teach people with multiple backgrounds and strengths is a real skill and I for one think this guy's videos are very useful. Especially for the beginners and hobbyists. I don't want to spend 10 years starting from scratch learning how to code the "proper" way... I already had a career and spent years in college and I just want to learn enough to make my VN's and continue this hobby. If that means my code is done differently than yours... so what? If it works, it works.

And as I learn more, I am confident enough to start to make my own "style". Stuff that makes sense to someone who has been coding from the Fortran days is like Sanskit to me. So I am slowly developing my own styles and naming conventions and what not. I'm sure it would probably make you curse and throw up your arms, but it works for me and it is (so far) working without many bug reports. In fact, most of the bugs I fix are either typos or errors in logic when I have multiple paths.

In any case, I think people can decide for themselves if his YT videos are worth it for them. I for one think they are very good for new programmers and game developers, who want to use Ren'py.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,384
15,291
Matt is very open about being self taught, so of course his path to a goal is not going to follow the "standard".
It's not a question of standard, just a question of common sense.

Python equivalents exist for the case where you need a feature from inside Python code, not to be used from a label. And because of this, not only it's more limited (by example you can't have transition when displaying the screen), but also less easy to use. Without counting the fact that the screen can't be predicted if shown through the Python equivalent, and will not be included in the lint process.
It's precisely the reason why they are always presented after the statements, when not on a different page. They are an alternative to use for really specific cases, not the main approach.

What he's doing is like teaching how to use a unicycle to people who own a 750 motorbike, while telling them that it's the best way to travel to the other side of the country.
So, yeah, with him you'll know how to master the use of unicycle, but you'll still have 1,000 km (if you're lucky to live in Europe were countries are small) in front of you, and will need tiring days before you reach your destination.


And yet, in Ren'py... even with as little knowledge as I have taught myself so far ... it is obvious that there are usually several ways to achieve a result.
There's several way, of course, and I'm among the ones who remind it regularly. But when you decide to teach something, the least one can do is to do it correctly. Not by teaching "the right way", but by teaching the easiest way, that generally double as the most efficient one.
Because whatever how good you can be at teaching, in the end viewers will be alone face to their code, and alone face to its issues.


There's lots of technicians I work with who are better pure mechanics (what we call "wrenches") but I have honestly never met a person that can understand how systems interact as well as I do.
Well, isn't it a reason more to teach the easiest and most efficient way ? That way 99% of the time they'll not need to know how they interact together.

Isn't it better to just have a statement, that will automatically fill a variable for you, that having to remember that you need to assign the value to a variable ?

Python:
label whatever:
    call screen whateverScreenName
    if _return == "whatever value":
        [do something]
Versus:
Python:
label whatever:
    $ returnValue = renpy.call_screen( "whateverScreenName" )
    if returnValue == "whatever value":
        [do something]
How many will not remember the leading "$", and pass minutes, when not hours, before figuring it ?
85% of what they'll find regarding the content of Ren'Py labels, including their working code, will show them that you don't need a leading "$". And to find it in the doc you need to look somewhere else that the parts talking about labels.

How many will not remember to assign the returned value, and wonder why it doesn't work ?
If they search for something like "get the value return by a Ren'Py screen", most of what they'll find will talk about call screen, and therefore not have that assignation. If they are beginners, they'll not understand that it's different with renpy.call_screen(), believing that they behavior are the same.

How many will want to pass a parameter, and not understand why Ren'Py complain ?
If you've a screen declared with screen myScreen( first=None ):, call screen myScreen( "Something" ) will works, but depending on what version of Ren'Py they'll use, renpy.call_screen( "myScreen", "Something" ) will not necessarily works.
From memory it was definitively fixed around the version 7.4.0, before this you had to explicitly use a keyword argument. Even me, who know about the issue and faced it often, still forget about it once in a while when I works on my variable viewer or any code that need to be compatible with older versions.


If that means my code is done differently than yours... so what? If it works, it works.
The key point is the last sentence...
I don't question your code, this is a generic question, but does it really works ?

Take a game like Corruption, that is finished since two years now. There's a never fixed bug that prevent you to see two third of the content in the casino. It's just an error in few conditions, so there's no crash. And like players don't know what is supposed to happen here, only those who looked at the code know that there's a bug.
It looks like it works, feel like it works, but it doesn't.

Another classical is the wrongly declared variables like:
Python:
label whatever:
    menu:
        "Do you spy at the marvelous naked girl ?"
        "Yes":
            $ spied = True
        "No":
            pass
Then later the "spied" variable will be tested, and anyone who decided to not spy will have a crash, because for them the variable do not exist. But who's dumb enough to not spy at the marvelous naked girl while playing an adult game ? So, near to no one will ever know that the game is broken.
I don't remember their names, but there's a dozen games currently in development that have this in almost all updates. And when it's really a choice as basic as this one, the bug is still present after many updates, because no one encountered it.

Of course, using call screen in place of renpy.call_screen() will not magically prevent bugs to happen. But it will generate warnings when you lint your code, while limiting the risk for them to happen, because the syntax is more intuitive.
And like it's the natural way to process, the one promoted by the documentation, you'll easily find what you are looking for if you face a bug at that level.


So I am slowly developing my own styles and naming conventions and what not. I'm sure it would probably make you curse and throw up your arms, [...]
You should read me more often if you think it's the way I would react.