Ren'Py Adding an achievement system

Daisuke Kanbe

Newbie
Game Developer
Nov 8, 2020
87
471
Hi, I am trying to add an achievement system to my game, where you pick an option and it pops a message of achievement unlocked and an image is unlocked on a separate screen called achievements where you can click on it and see the image fullscreen.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
But let's cover the generic basics...
This post is intended to be a narrative to explain the links I've provided. Your answer is going to come from following the links and reading the information there.


How to track achievements

Achievements are usually implemented by the game tracking something happening once within game.
One common way is to track if a specific image has been shown to the player. If the player does the right things, then the image is shown, perhaps a popup "woohoo" is shown and the achievements gallery checks to see if the picture has been flagged by RenPy as being shown to the player.

You do this checking . RenPy tracks all images shown while the game is playing, so it's a good way of tracking achievements. The check is "persistent" - that is, it is not dependent on save files or an individual playthrough. If you replay a game with multiple paths/routes, any images seen during playthrough #1 are still unlocked while playing through playthrough #3. Which makes it a good solution for achievements, that tend to be game wide.

An alternative is . But this is much less common. Same idea, but using the name of label: statements rather than the name of images.

Other developers choose to not to let RenPy do the heavy lifting and instead track things themselves. Again, RenPy has a persistent solution, in this case imaginatively called . You may or may not already be aware that "normal" variables within your game are kept within a data store called store. It's usually invisible to you, but effectively RenPy doesn't save individual variables - instead just dumps the whole store to your save files. Another data store is called persistent. If you prefix your variable name with persistent, then it will be stored there. Persistent variables like the "seen" data is independent of the current playthrough.

So you could have a line like $ persistent.ach01_unlocked = True to set the achievement #1 and if persistent.ach01_unlocked == True: as part of your gallery code to see if the achievement gallery can be shown or not.

RenPy even has an . Though honestly, I don't ever recall seeing it used. It is just a more structured way of using persistent data.


Showing a popup

I've done this, but can't find an example bit of code quickly while writing this.

The basics are that you show an image using some sort of or . Ideally with an accompanying at the same time. The animation could be as complex as you like or as simple. The most common solution I see is an image which is displayed in one of the corners of the screen for a few seconds before fading out. Though you could get more creative and have an image appear, then both scroll up off the screen while at the same time fading out or shrinking in size. Or anything else you can imagine.


The achievement gallery

The usual solution is to create a which shows images. Though more complex versions can also make use of RenPy's system to replay sections of your code/game.

Again, RenPy has a that some developers use and others avoid like the plague.
Another solution is a variation on this gallery system.
... and many other variations on a theme.


"Borrow someone else's code"

By far the best way to implement this, if you are struggling, is to "borrow" someone else's code.
Pick a game (or ideally a couple of games) where you've seen achievement systems used and take a look how they did it. Cherry pick the best bits that suit your game and leave the rest behind.
Keep in mind that most AVN developers are not experts - their code is going to be badly written or very rarely, buggy. Don't just copy stuff wholesale - otherwise you won't understand how it to fix it if something goes wrong.

The starting point though is likely to be UnRen. A tool which unpacks RenPy archives and rebuilds the source code files if they omitted from the game's distribution. Not all games need UnRen to see the *.rpy source code files, but a lot do. Very rarely, you'll only be able to find .rpyc files and not their source code. UnRen can rebuild the .rpy files based on the data stored in the .rpyc files.


Keep it simple

Finally, a note of caution.
A lot of new developers think they need to add complex solutions to their game in order to keep up with the more established games. They've seen something done in another game, liked it... and so want to do the same in their own game. Except... programming these solutions is complex and often very hard work for an inexperienced developer. The usual suspects are "an inventory system", "a gallery", "an open world game" and "achievements". Theses are all "nice to have" within games, but not essential. If you never told your potential players that you were thinking of adding an achievement system - nobody would ever miss it.
Sometimes it's better to finish a simple game than abandon development of a more complex game.
Or put another way... players tend to play for the tits, ass and story. Achievement systems aren't even on their radar. Think about keeping it simple.
 
Last edited:

Daisuke Kanbe

Newbie
Game Developer
Nov 8, 2020
87
471
But let's cover the generic basics...
This post is intended to be a narrative to explain the links I've provided. Your answer is going to come from following the links and reading the information there.


How to track achievements

Achievements are usually implemented by the game tracking something happening once within game.
One common way is to track if a specific image has been shown to the player. If the player does the right things, then the image is shown, perhaps a popup "woohoo" is shown and the achievements gallery checks to see if the picture has been flagged by RenPy as being shown to the player.

You do this checking . RenPy tracks all images shown while the game is playing, so it's a good way of tracking achievements. The check is "persistent" - that is, it is not dependent on save files or an individual playthrough. If you replay a game with multiple paths/routes, each images seen during playthrough #1 are still unlocked while playing through playthrough #3. Which makes it a good solution for achievements, that tend to be game wide.

An alternative is . But this is much less common. Same idea, but using the name of label: statements rather than the name of images.

Other developers choose to not to let RenPy do the heavy lifting and instead track things themselves. Again, RenPy has a persistent solution, in this case imaginatively called . You may or may not already be aware that "normal" variables within your game are kept within a data store called store. It's usually invisible to you, but effectively RenPy doesn't save individual variables - instead just dumps the whole store to your save files. Another data store is called persistent. If you prefix your variable name with persistent, then it will be stored there. Persistent variables like the "seen" data is independent of the current playthrough.

So you could have a line like $ persistent.ach01_unlocked = True to set the achievement #1 and if persistent.ach01_unlocked == True: as part of your gallery code to see if the achievement gallery can be shown or not.

RenPy even has an . Though honestly, I don't ever recall seeing it used. It is just a more structured way of using persistent data.


Showing a popup

I've done this, but can't find an example bit of code quickly while writing this.

The basics are that you show an image using some sort of or . Ideally with an accompanying at the same time. The animation could be as complex as you like or as simple. The most common solution I see is an image which is displayed in one of the corners of the screen for a few seconds before fading out. Though you could get more creative and have an image appear, then both scroll up off the screen while at the same time fading out or shrinking in size. Or anything else you can imagine.


The achievement gallery

The usual solution is to create a which shows images. Though more complex versions can also make use of RenPy's system to replay sections of your code/game.

Again, RenPy has a that some developers use and others avoid like the plague.
Another solution is a variation on this gallery system.
... and may other variations on a theme.


"Borrow someone else's code"

By far the best way to implement this, if you are struggling, is to "borrow" someone else's code.
Pick a game (or ideally a couple of games) where you've seen achievement systems used and take a look how they did it. Cherry pick the best bits that suit your game and leave the rest behind.
Keep in mind that most AVN developers are not experts - their code is going to be badly written or very rarely, buggy. Don't just copy stuff wholesale - otherwise you won't understand how it to fix it if something goes wrong.

The starting point though is likely to be UnRen. A tool which unpacks RenPy archives and rebuilds the source code files if they omitted from the game's distribution. Not all games need UnRen to see the *.rpy source code files, but a lot do. Very rarely, you'll only be able to find .rpyc files and not their source code. UnRen can rebuild the .rpy files based on the data stored in the .rpyc files.


Keep it simple

Finally, a note of caution.
A lot of new developers think they need to add complex solutions to their game in order to keep up with the more established games. They've seen something done in another game, liked it... and so what to do the same in their own game. Except... programming these solutions is complex and often very hard work for an inexperienced developer. The usual suspects are "an inventory system", "a gallery", "an open world game" and "achievements". Theses are all "nice to have" within games, but not essential. If you never told your potential players that you were thinking of adding an achievement system - nobody would ever miss it.
Sometimes it's better to finished a simple game than abandon development of a more complex game.
Or put another way... players tend to play for the tits, ass and story. Achievement systems aren't even on their radar. Think about keeping it simple.
Thank you so much for taking your time and explaining it thoroughly. This is exactly what I was looking for and it is very helpful. Thanks a lot!
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,284
RenPy even has an . Though honestly, I don't ever recall seeing it used. It is just a more structured way of using persistent data.
So far I've seen it used in only one game ; that I don't like what led me to totally forgot which one it was :(

I think that it frightens devs, at least those who know it exist, more than anything. The doc starts with:
achievement.Sync()
An action that calls achievement.sync(). This is only sensitive if achievements are out of sync.
And boom, it already seem "so complicated while I've seen it done in that game, the guy just had a bunch of boolean variables he turned to True when needed".
 
  • Like
Reactions: Tribe and 79flavors