Quick tutorial: gallery in Ren'Py

Come For A Drink is my first game (ever) and also my first time using Ren'Py, a visual novel engine. I was pleasantly impressed with all the features available (especially the tutorial game packaged with the engine), however, I struggled with the official documentation, because I'm a python/game making newbie, overall it wasn't visual enough for me (a visual learner), and I also struggled to understand, architecturally, how all the rpy files worked together (or separately) when packaged.

Here's a quick visual tutorial on making a gallery in Ren'Py 7.0. Galleries are a nice way to track your progress in game (if you have multiple endings) and/or show off that fancy CG you made that would otherwise only be seen for a split second during game play.

Please note that I'm NOT an expert, I don't understand all this code, but this is working code that is in my game! It is the result of a lot of uninformed trial and error.

A. Create the gallery code (in gallery.rpy) and associate them with your image files

What I've garnered from the internet is that it doesn't really/quite matter which rpy file you put your code into. I made an entirely new gallery.rpy file (same root folder as all your script/options/screens files) and dumped the code in there for my own sanity/testing purposes. Full code for this part is at the end of PART A.

Let's unpack each bit of the code, sequentially.

init python:

   # Step 1. Create the gallery object.
    g = Gallery()

    g.locked_button = "locked.png" #this is the thumbnail image for ALL LOCKED gallery previews, found in the images folder

Image description

   # Step 2. Add buttons and images to the gallery.

   # A button that contains an image that automatically unlocks.
    g.button("ending1") #this is the name/label associated with your button for a particular image, can be modified
    g.condition("persistent.unlock_1") #this is the requirement/condition that must be met for this gallery image to unlock
    g.image("backgroundImageName1", "foregroundImageName1") #this creates a gallery image that overlaps a foreground on top of a bg, you can also use a single flattened image here 

Image description

g.button("ABCDEFG") The ABCDEFG name/label can be whatever you want; I have "ending1", but yours could be "gallery_image01" or what have you, as long as you remember what it is, because it comes back in step 3.

g.condition("persistent.unlock_ABCDEFG") I think you could potentially change the ABCDEFG of the condition name/label; I have persistent.unlock1 (where 1 is the name of my condition), but you could maybe try persistent.unlock_insertYourNewConditionNameHere?

Sometimes you want players to meet multiple conditions to be able to unlock your fancy gallery image. In my game, the player can only unlock the bonus content if they get all 9 endings, so I have multiple conditions listed, separated by and:

    g.button("bonus10")
    g.condition("persistent.unlock_1 and persistent.unlock_2 and persistent.unlock_3 and persistent.unlock_4 and persistent.unlock_5 and persistent.unlock_6 and persistent.unlock_7 and persistent.unlock_8 and persistent.unlock_9")  
    g.image("bonus10")

g.image("ABCDEFG", "HIJKLMNOP") You can call in multiple images in order of background to foreground and create a final gallery image that is displayed when the player clicks on the (eventually unlocked) thumbnail. In this example, I have a background image named "backgroundImageName1" and a foreground image named "foregroundImageName1", both found in my images folder. You don't have to include the filename extension. You can also use a single image here if you don't want to rely on Ren'Py to generate the final gallery image for you (get rid of , "HIJKLMNOP") .

For each gallery image, you need to define:

  • unique name/label g.button("ABCDEFG")
  • condition(s) g.condition("persistent.unlock_ABCDEFG")
  • final gallery image(s) g.image("ABCDEFG", "HIJKLMNOP")

I have 11 in total. Once you have defined the above for each gallery item, we need the code that defines how the gallery appears on screen/in-game.

    #Step 3: generate the gallery and how it looks
screen gallery:

   # Ensure this replaces the main menu.
    tag menu

   # The background.
    add "bg_ceiling" #this is the bg image for the gallery; found in the images folder

Image description

By default the gallery replaces your game menu screen, which makes sense to me. To be honest, I only modified the background image of the gallery to be "bg_ceiling" (again, no file extension needed) found in my images folder.

Next we put our gallery thumbnails onto the gallery screen. I used a 4 (horizontal) x 3 (vertical) grid, which means I'd have 12 spots total for thumbnails...well, that's what I thought, but I only have spots for 11 images because it appears that one of the spots might be taken up by the "Return" link. Truth be told, I modified the amount of gallery content I had based on the fact that I couldn't figure out how to get the grid to work, HAHA.

# A grid of buttons.
    grid 4 3:

        xfill True
        yfill True

        # Call make_button to show a particular button.
        add g.make_button("ending1", "unlock1.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending2", "unlock2.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending3", "unlock3.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending4", "unlock4.png", xalign=0.5, yalign=0.5)

        add g.make_button("ending5", "unlock5.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending6", "unlock6.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending7", "unlock7.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending8", "unlock8.png", xalign=0.5, yalign=0.5) 

        add g.make_button("ending9", "unlock9.png", xalign=0.5, yalign=0.5)  
        add g.make_button("bonus10", "unlock10.png", xalign=0.5, yalign=0.5)      
        add g.make_button("bonus11", "unlock11.png", xalign=0.5, yalign=0.5)  

        #return to main menu
        textbutton "Return" action Return() xalign 0.5 yalign 0.5

Image description

The variables here are:

  • unique name/label (e.g., ending1), which should be the SAME as the unique name/label you defined in Step 2
  • unlocked thumbnail image file (e.g., unlock1.png, also found in your images folder)
  • position within the grid (e.g., xalign=0.5, yalign=0.5, which in this case horizontally and vertically centre aligns the image to the midpoint of the grid cell)

Here's what the gallery grid looks like when it's up and running. Sorry, my gallery is completely unlocked, so I had to mosaic images out, so it looks extra ugly. In your version, if everything is working out, it's likely that the "locked.png" thumbnail is shown here in lieu of my gross mosaic images, since you haven't coded in the unlock conditions into your game script yet. Also to note, you have no real way to navigate/get to your gallery screen yet to test if it works/looks the way you want, but that will be addressed in Part B.

Image description

This was the hardest part of the tutorial. Save and close out of gallery.rpy!

Full code for this gallery.rpy part is below, which includes 11 gallery items.

###############GALLERY##################
init python:

   # Step 1. Create the gallery object.
    g = Gallery()

    g.locked_button = "locked.png" #this is the thumbnail image for ALL LOCKED gallery previews, found in the images folder

   # Step 2. Add buttons and images to the gallery.

   # A button that contains an image that automatically unlocks.
    g.button("ending1") #this is the name/label associated with your button for a particular image
    g.condition("persistent.unlock_1") #this is the requirement/condition that must be met for this gallery image to unlock
    g.image("backgroundImageName1", "foregroundImageName1") #this creates a gallery image that overlaps a foreground on top of a bg, you can also use a single flattened image here 

    g.button("ending2")
    g.condition("persistent.unlock_2")
    g.image("backgroundImageName2", "foregroundImageName2")

    g.button("ending3")
    g.condition("persistent.unlock_3")
    g.image("backgroundImageName3", "foregroundImageName3")

    g.button("ending4")
    g.condition("persistent.unlock_4") 
    g.image("backgroundImageName4", "foregroundImageName4")

    g.button("ending5")
    g.condition("persistent.unlock_5")
    g.image("backgroundImageName5", "foregroundImageName5") 

    g.button("ending6")
    g.condition("persistent.unlock_6")
    g.image("backgroundImageName6", "foregroundImageName6")

    g.button("ending7")
    g.condition("persistent.unlock_7")
    g.image("backgroundImageName7", "foregroundImageName7")

    g.button("ending8")
    g.condition("persistent.unlock_8")  
    g.image("endingImageName8") 

    g.button("ending9")
    g.condition("persistent.unlock_9")  
    g.image("endingImageName9")

    g.button("bonus10")
    g.condition("persistent.unlock_1 and persistent.unlock_2 and persistent.unlock_3 and persistent.unlock_4 and persistent.unlock_5 and persistent.unlock_6 and persistent.unlock_7 and persistent.unlock_8 and persistent.unlock_9")  
    g.image("bonus10")

    g.button("bonus11")
    g.condition("persistent.unlock_1 and persistent.unlock_2 and persistent.unlock_3 and persistent.unlock_4 and persistent.unlock_5 and persistent.unlock_6 and persistent.unlock_7 and persistent.unlock_8 and persistent.unlock_9")  
    g.image("bonus11")  

    #Step 3: generate the gallery and how it looks
screen gallery:

   # Ensure this replaces the main menu.
    tag menu

   # The background.
    add "bg_ceiling" #this is the bg image for the gallery; found in the images folder

   # A grid of buttons.
    grid 4 3:

        xfill True
        yfill True

        # Call make_button to show a particular button.
        add g.make_button("ending1", "unlock1.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending2", "unlock2.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending3", "unlock3.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending4", "unlock4.png", xalign=0.5, yalign=0.5)

        add g.make_button("ending5", "unlock5.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending6", "unlock6.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending7", "unlock7.png", xalign=0.5, yalign=0.5)
        add g.make_button("ending8", "unlock8.png", xalign=0.5, yalign=0.5) 

        add g.make_button("ending9", "unlock9.png", xalign=0.5, yalign=0.5)  
        add g.make_button("bonus10", "unlock10.png", xalign=0.5, yalign=0.5)      
        add g.make_button("bonus11", "unlock11.png", xalign=0.5, yalign=0.5)  

        #return to main menu
        textbutton "Return" action Return() xalign 0.5 yalign 0.5

B. Add the link to your gallery to the game menu (screens.rpy)

Assuming you haven't made any big modifications to the language in your screens.rpy, open the file, search for the code screen navigation():, and navigate down to the else: statement, add the last line of code in the snippet below:

       else:

            #textbutton _("History") action ShowMenu("history")

            textbutton _("Save") action ShowMenu("save")

        textbutton _("Load") action ShowMenu("load")

        textbutton _("Settings") action ShowMenu("preferences")

        textbutton _("Gallery") action ShowMenu("gallery") #GALLERY LINK ADDED HERE

Last line of code adds the Gallery menu item to the game screen. In my version of the code, I commented-out the History link that were there by default, but you can keep yours in if you want.

Image description

FYI, the name "gallery" is arbitrary, but you need to call it the same thing between your gallery.rpy screens.rpy files.

Image description

Now you can save and close your screens.rpy file, reload your game, and click the "Gallery" link. It should bring you to the gallery page.

Image description

C. Add persistent unlocks to your gameplay (in script.rpy)

So your gallery screen works, but the gallery images are all LOCKED. Time to code in the conditions that the player needs to meet in order for the special image to be unlocked. In my game, the conditions were pretty straightforward, e.g., they had to get to a specific point in the dialogue. I just dumped the unlock code in the appropriate spot in my script.rpy file where the player needed to get to (in the dialogue) in order for the unlock to happen.


    p "Hello, I'm person p. Do you want to go out with me?" #fake dialogue

    y "I would love to!!!!!!!!!!"  #fake dialogue

    $ persistent.unlock_9 = True #once this interaction between person p and y has happened, they have met the condition for ending 9 to be unlocked.

If you recall from working on gallery.rpy, persistent.unlock_9 is the condition that needs to be met in order to unlock the gallery image 9.

Image description

For purposes of testing, I saved and closed out of script.rpy and reloaded the game,

I played through the game, knowing and making choices that will meet that conditions required to unlock ending 9 (aka reach the point in the dialogue where the game will know that $ persistent.unlock_9 = True), then revisited the gallery afterwards to see if the image was unlocked. After I felt confident that things were in working order, I added the rest of the $ persistent.unlock_ABCDEFG = True (for gallery images 1-11) throughout the script.

One thing to note is that when you package the file for distro/playing, you computer keeps your persistent data on your harddrive, so when you re-open your packaged game to play, you'll see that your game remembers what you've unlocked. Internet tells me that since the persistent data it's unique to your HD, other people won't have that presistent data on their HD when they download and play it on their computer, therefore, they will only see locked images until they themselves, meet the right conditions through game play.

That's all for now! More info/tutorials related to gallery making are below: