Ren'Py Achievements Framework
A downloadable tool
This framework (BobCAchievements) is intended to be an easy way to add achievements to your Ren'Py game. It should also be compatible with Steam (and other app stores). It also provides lint validation for your game script's achievement granting.
Directions for use are included in the source files, or follow along below!
This framework is provided under the Unlicense and released into the public domain, and no attribution or further licensing is necessary. Feel free to modify it to suit your use case! (If you do wish to attribute me, a link to bobcgames.com would be greatly appreciated.)
This framework is provided "as is" without warranty of any kind. Basic help can be provided in the project discussion board, or visit the Ren'Py Discord server for more complex customizations.
Also check out my other Ren'Py Frameworks, Tools, and Game Dev Resources!
How To Use
The TL;DR is: Download the file, update the achievement list, and grant achievements in your Ren'Py game code!
You can also easily customize the way the achievements are displayed when unlocked, and add a screen for the user to view all of their achievements!
Download The File
To get started, download the 0bobcachievements.rpy
file and drop it into the game/
folder of your Ren'Py game project.
(Do not rename this file, or achievements may not behave properly, or your game may not run.)
Update The Achivement List
Open the 0bobcachievements.rpy
file up in your favorite text editor. The first thing to do is add your achievements to the defined BOBCACHIEVEMENT_LIST at the top of the file.
define BOBCACHIEVEMENT_LIST = ( ("started", _("Started The Game"), _("A sample achievement you can grant when the player starts the game.")), ("samplehidden", _("My First Achievement"), _("A sample achievement to demonstrate usage of hidden achievements."), True), )
For example, the predefined code defines two achievements. The first has a reference_id of started
, a user-friendly title of Started The Game
, and an associated user-friendly description. The second has a reference_id of samplehidden
and a user-friendly title of My First Achievement
, and is marked as hidden.
Update this list with all of your desired achievements, and delete the two starting ones if you do not wish to include them.
The framework should raise fairly descriptive errors during game launch if you configure something improperly in here. Start your game often as you're adding achievements if you're worried about the formatting.
Keep in mind that, as a best practice, reference IDs should be alphanumeric strings with no spaces. This value will not ever be shown to the player, so you don't need to worry about how it looks.
If you're adding achievements in Steam, these reference IDs are the API names you should use for your achievements.
Grant Achievements In Your Game Code
After you have defined all of your achievements in the list, you need to actually grant them to players as they play your game!
In your game code, simply type achieve reference_id
to grant the achievement associated with that reference_id.
For example, to grant the "Started The Game" achievement (with reference ID started
) when the game starts, your script.rpy would look something like:
label start: scene bg room show eileen happy e "You've created a new Ren'py game." achieve started e "Once you add a story, pictures, and music, you can release it to the world!" return
(If you're doing more complicated things with Python code, you can also directly grant the achievement via a function call as bobcachievement_grant("started")
)
This is all you need to do! You now have achievements in your game that will work with Steam. However, read on for further (optional) customizations.
Optional: Customize The Achievement Unlocking Display
By default, this framework uses renpy.notify to show that an achievement was unlocked by the player. To switch to a screen that you can customize, simply replace line 41 of 0bobcachievements.rpy
with the following:
define BOBCACHIEVEMENT_SCREEN_NAME = "bobcachievement_samplescreen"
(You can also use your own custom screen name.)
Customize the screen by updating the defined bobcachievement_samplescreen
screen, for example by adding an image or a background, or changing the text color!
Optional: Add A Screen To View Unlocked Achievements
Download the sbobcachievements.rpy
file and drop it into your game/
folder.
Next, open the existing screens.rpy
file (also located in your game/
folder) in a text editor. Search for screen navigation():
and locate the line that adds the "Preferences" button. Add the following code below that line, ensuring that the indentation matches:
textbutton _("Achievements") action ShowMenu("bobcachievements")
This means your code should now look something like this:
textbutton _("Preferences") action ShowMenu("preferences") textbutton _("Achievements") action ShowMenu("bobcachievements")
That's all you have to do! You can now click the new "Achievements" button from the main menu or any game menu and view a list of achievements.
(Note that any achievement marked as "hidden" in the list of achievements BOBCACHIEVEMENT_LIST will not show its name until it has been unlocked. All other achievements will show their names, but not descriptions, if they are still locked.)
You can customize the screen to your liking as well in the sbobcachievements.rpy
file.
Frequently Asked Questions
(For some definition of "Frequently Asked")
Why are the achievement titles and descriptions enclosed in _("")
?
The _()
function in Ren'Py is used to mark text as available for translation (see the Ren'Py documentation). By enclosing your achievement titles and descriptions in this function, you are ensuring that your achievement names and descriptions are properly translated, along with the rest of your game.
(Note: If you are customizing screens, remember that Ren'Py translates on display, such as via the text
screen element.)
Shouldn't I type $ achieve started
?
No! Starting a line with $
in Ren'Py tells the engine to interpret that line as Python code.
In this case, we have defined a creator-defined statement (CDS) for achievements instead, which allows you grant achievements more directly in your game's script. We use this instead of a python function invocation to grant achievements.
The benefits of CDSes are many, but in particular, CDSes can be validated as part of the lint process (as the achieve
command here is!) while Python code cannot be, and will instead fail at runtime.
(If you aren't already, you should be in the habit of regularly running lint on your game via the Ren'Py launcher, as it will help detect many problems that would either crash your game, or cause unintended behavior.)
What is a "hidden" achievement?
Sometimes even the name of an achievement can be a spoiler, and you want to keep it hidden from the player until they unlock it.
When you use the provided achievement screens (via sbobcachievements.rpy
), the framework will hide the names of these achievements in the Achivements screen until they are unlocked.
Marking an achievement as "hidden" only has meaning for the included UI screen. (Although you can, of course, make use of this information yourself in screen customizations.)
Note: This does not affect how Steam handles achievements. You will need to configure hidden achievements separately, and manually, within Steamworks.
The achivements aren't showing in order on the Achievements screen
Make sure you're using Ren'Py 8 or later. Ren'Py 7 and earlier will not display the achievements in order due to how Python 2.7 handles dicts.
Download
Click download now to get access to the following files: