Cross-posted from tumblr

Here’s this week’s update! I carried on working on the GUI trying to use as few imagebuttons as possible to avoid having to keep editing/exporting images and because I wanted to see just how much I could do with just renpy stlying.

The first update since last week was to add the slide in transform I’d wanted to use for the menu options:

$ delay = 0.15
$ offset = 0.07
transform slidein1:
    alpha 0.0 xpos 770 ypos 140
    pause delay + offset
    ease 0.2 alpha 1.0 xpos 820 ypos 30
transform slidein2:
    alpha 0.0 xpos 790 ypos 250
    pause delay + (offset * 2)
    ease 0.2 alpha 1.0 xpos 880 ypos 170
transform slidein3:
    alpha 0.0 xpos 790 ypos 250
    pause delay + (offset * 3)
    ease 0.2 alpha 1.0 xpos 900 ypos 220
transform slidein4:
    alpha 0.0 xpos 790 ypos 300
    pause delay + (offset * 4)
    ease 0.2 alpha 1.0 xpos 910 ypos 315
transform slidein5:
    alpha 0.0 xpos 770 ypos 330
    pause delay + (offset * 5)
    ease 0.2 alpha 1.0 xpos 890 ypos 390
transform slidein6:
    alpha 0.0 xpos 770 ypos 350
    pause delay + (offset * 6)
    ease 0.2 alpha 1.0 xpos 820 ypos 463

This makes each menu item fade in and slide out from the centre of the circle when entering the menu. As you’ll see at the top I set two variables to make it easier to adjust the speed of the animation. Delay is the amount of time to pause after the menu is shown before starting the animation. Offset is the amount of gap between one menu item being animated and the next. Setting all the custom coordinates for each transform was very annoying but the effect is definitely worth it. I’m just sad I can’t manage to capture it in gif format because it happens very quickly and the framerate of what I’m using for gifs can’t keep up. So I guess, look forward to seeing that in the finished game (or at least the demo) haha.

Now for the save/load menu. I started off by thinking of things that I wanted and that would be helpful for me in a save/load menu. First of all I really wanted a feature that added what was being said at the time of the save because with just a tiny screenshot it’s often not enough to jog my memory (I have a habit of leaving games for months and then coming back not knowing what I was supposed to be doing). Then I thought another nice thing to have would be a playtime counter. This would add a bit more context to the save file - depending on how much playtime I’d know how far into the game I was. To add these features I added my own custom python functions:

def save_playtime(d):
    d["playtime"] = renpy.get_game_runtime()
config.save_json_callbacks = [save_playtime]

def format_playtime(playtime):
    minutes, seconds = divmod(int(playtime), 60)
    hours, minutes = divmod(minutes, 60)
    return "{}hr {}m".format(hours, minutes)

save_playtime gets the runtime and saves it with the game save data. More info on renpy.get_game_runtime and config.save_json_callbacks.

format_playtime returns the playtime in an easy to read format. Since renpy saves the playtime in seconds and decimals we format it to hrs, mins, secs using the python built in function divmod. This returns the quotient and remainder when dividing the first argument (time) by the second (60), giving us the mins and secs, then hrs and mins. Then we use another python function .format to put these variables into the string returned by the function.

Then we can add the playtime to the file slot like so:

$ playtime = format_playtime(FileJson(slot, "playtime", empty=0, missing=0))
# Add description
$ slot_name = FileSaveName(slot)
vbox:
    if slot_name:
        fixed:
            style "file_slot_text_fixed"
            text "[slot_name]" style "file_slot_text_description"
        text "Playtime: [playtime]" style "file_slot_text_playtime"

To add the save description I made these two other functions:

def get_save_description(who, what):
    if who == 'N' or who == 'NVL':
        return truncate_text(what)
    else:
        return truncate_text('{}: "{}"'.format(who, what))

def truncate_text(long_text):
    max_length = 70
    if len(long_text) > max_length:
        return "{}...".format(long_text[:max_length])
    else:
        return long_text

get_save_description takes the current who and what that is shown in the say box (unless the who is ‘N’ (narrator) or ‘NVL’) and formats it into a string that can be displayed in the file slot. Since the file slots are a fixed size I had to make truncate_text to cut down the length of the text so it doesn’t overflow. The max_length in characters is set to 70 then a simple if statement checks if the text is longer or shorter and truncates it accordingly with long_text[:max_length] which returns all characters up to max_length (the ‘:’ is important!).

Another cool thing I did this week was to reorganise all my game folders so I could find things more easily. Having one or two long files for script, options, and screens looked neat in the file structure but was awful when navigating individual files - I had to keep using ctrl+f to move around a file that was 5000+ lines). I’d already decided to split up the script files according to labels but now I had a very long list of .rpy and .rpyc and .bak files in my game folder and that wasn’t nice to navigate either. So I decided to make subfolders and organise them by story timeline - a folder for each day of the script. I also made separate folders for screens, fonts, and config. Here’s the new file structure for the game:

metamorphoser-v2
  ∟ game
    ∟ cg
      config
        ∟ options.rpy
      fonts
        ∟ font files
      gallery
        ∟ gallery thumbnails
      gui
        ∟ gui images
      scene
        ∟ background images
      screens
        ∟ choice.rpy
          gallery.rpy
          input.rpy
          mainmenu.rpy
          nvl.rpy
          rcmenu.rpy
          saveload.rpy
          say.rpy
          settings.rpy
          yesno.rpy
      script
        ∟ 01-monday
          ∟ script files for monday
        ∟ 02-tuesday
          ∟ script for tuesday
        ∟ 03-wednesday
          etc
      sound
        ∟ sound/music files
      sprite
        ∟ sprite images

This has turned out to be a much nicer way to navigate the project. I’d much rather be editing lots of very small files than one very big files that is hard to navigate. The script folders were named 01-monday, 02-tuesday, etc with the numbers to keep them in order, otherwise the file system would arrange them alphabetically not chronologically.

I have a lot of other stuff I could talk about that I worked on this week but then this would become a very long post!! In future I’ll talk about styling the GUI a bit more.