Renpy Pirate Game Part 6 - Styles, Scoring, Inventory System

by IoFAdmin at

renpy | python | programming

Our Previous Trip On the High Seas...

In our last post, we learned all about Renpy variables, conditionals and screens. We'll build on those concepts in this post.

Programming Notice!

For brevity's sake, I'll only be showing code that has changed since last post instead of all of the code. (Your noticing the notice has been noticed.)

Sailing Ever Onward

We'll be exploring three concepts in this tutorial:

  • Styles
  • A Scoring System
  • An Inventory System

So What Are Renpy Styles?

Styles in Renpy allow us to change the appearance and layout of components in our game. If you've ever learned CSS for websites, it's similar in concept. While Renpy Styles can become quite complicated, we're keeping it pretty simple here. (See the Renpy documentation for more information on styles.)

Getting the High Score

To help the player and add a little extra fun, we're going to add scoring to our game. (By the way, how and what does a pirate score? A date? Some treasure? A bottle of rum?) When our player completes certain tasks in the game, he/she will receive points. To complete the current level, our player will have to complete all of the required tasks (and score all of the points).

An Inventory System... AKA Our Pirate Treasure

If you remember from our last post, our pirate hero found a house key when he investigate the potted plant in front of his house. We set a variable, hasHouseKey, to keep track of whether he collected the key or not. Since we're going to have many more items in the future, setting a variable for each one will get to be impractical. An inventory system will solve our problem. We'll be visualizing our inventory with a backpack.

X Marks the Spot... For Our Code

Keeping with the format of the previous posts, I'll show you the code and then explain it. We'll start with script.rpy from post #5. Like I mentioned earlier, we'll only be looking at code that has changed so your code will be longer than what's shown here.

default inventory = []

label start:
    scene bg insidehouse
    show pirate happy
    show screen hudScreen

    $ points = 0
    $ player_name = renpy.input("What is your name?", length=10)
    $ player_name = player_name.strip()
    if player_name == "":
        $ player_name = "Sheldon"

    p "No Miss Fluffybottom! Wait!"
    "Your cat, the adventurous (and naughty) Miss Fluffybottom runs out the front door of your house. That bad kitty's chasing a bird again! You should probably go after her right meow."

    menu:
        "Go after her.":
            jump house_outside
        "She'll be fine.":
            jump house_inside

    return

label flower_pot:
    scene bg outsidehouse
    show pirate happy

    if 'house_key' in inventory:
        p "Mom's favorite plant could use some watering but I'll LEAVE it alone right now."
    else:
        $ inventory.append('house_key')
        $ points += 10
        p "Hey what's that? Looks like a house key! Now I have the key to my front door."

    jump front_porch

label house_outside:
    scene bg outsidehouse
    show screen frontPorchScreen
    show pirate happy

    p "There she is down on the beach chasing the seagulls again. Crazy cat! I should probably bring her back in the house before she gets lost or drowns."
    "The door slams shut and you're locked out of the house!"

    menu:
        "Use my key." if 'house_key' in inventory:
            hide screen frontPorchScreen
            jump house_inside
        "Knock on the door." if 'house_key' not in inventory:
            jump door_knock
        "Go after Ms Fluffybottom.":
            hide screen frontPorchScreen
            jump beach_squid

label front_porch:
    scene bg outsidehouse
    show screen frontPorchScreen
    show pirate happy

    p "My front porch."

    menu:
        "Use my key." if 'house_key' in inventory:
            hide screen frontPorchScreen
            jump house_inside
        "Knock on the door." if 'house_key' not in inventory:
            hide screen frontPorchScreen
            jump door_knock
        "Go after Ms Fluffybottom.":
            hide screen frontPorchScreen
            jump beach_squid

Another One

Open up myscreens.rpy and replace everything with the code below.

screen frontPorchScreen():
    imagebutton:
        xalign 0.75
        yalign 1.0
        idle "flower"
        action Jump("flower_pot")

screen hudScreen():
    frame style style["hud_frame"]:
        hbox:
            if player_name == "":
                label "Player"
            else:
                label player_name

            label "   Points: "
            text "%d  " % points

            imagebutton:
                idle "backpack"
                action Show("inventoryScreen")

screen inventoryScreen():
    modal True
    frame style style["inventory_frame"]:
        imagebutton style style["close_btn"]:
            idle "close"
            action Hide("inventoryScreen")

        vbox:
            text "Inventory"
            grid 7 4:
                for i in range(28):
                    frame:
                        maximum(155,155)
                        if i < len(inventory):
                            background Image(inventory[i]+".png")
                            $ inv_item_name = inventory[i].replace('_', ' ')
                            text [inv_item_name] style style["inv_item"]
                        else:
                            background Image("placeholder.png")

Arrrgh! This Be The Last One

Create a new file in the same directory as script.rpy, name it mystyles.rpy, and paste all of the following code into it.

style inv_item is text:
    size 16
    bold True
    color Color((0, 255, 0, 255))
    pos (5,125)

style inventory_frame is frame:
    xpadding 10
    ypadding 10
    xalign 0.5
    yalign 0.5
    xsize 1152
    ysize 660
    background Color((193, 66, 66, 192))

style close_btn:
    xpos 1100
    ypos -4

style hud_frame is frame:
    xpadding 10
    ypadding 10
    xalign 0.5
    yalign 0.0

So What Was All of That?

We'll start with script.rpy mateys.

default inventory = []

We replaced define hasHouseKey = False with default inventory = [] which is required to work with our screen code below.

label start:
    scene bg insidehouse
    show pirate happy
    show screen hudScreen

    $ points = 0

Here we're showing a new screen hudScreen (which we'll create later) and we have a new variable points that we'll use in our scoring system.

label flower_pot:
    scene bg outsidehouse
    show pirate happy

    if 'house_key' in inventory:
        p "Mom's favorite plant could use some watering but I'll LEAVE it alone right now."
    else:
        $ inventory.append('house_key')
        $ points += 10
        p "Hey what's that? Looks like a house key! Now I have the key to my front door."

    jump front_porch

In our flower_pot label, we're checking to see if house_key exists in our inventory variable. If it does, make a bad pun, else append it to our inventory list variable and give our player 10 points.

label house_outside:
    scene bg outsidehouse
    show screen frontPorchScreen
    show pirate happy

    p "There she is down on the beach chasing the seagulls again. Crazy cat! I should probably bring her back in the house before she gets lost or drowns."
    "The door slams shut and you're locked out of the house!"

    menu:
        "Use my key." if 'house_key' in inventory:
            hide screen frontPorchScreen
            jump house_inside
        "Knock on the door." if 'house_key' not in inventory:
            jump door_knock
        "Go after Ms Fluffybottom.":
            hide screen frontPorchScreen
            jump beach_squid

Same thing here... see if house_key is in our inventory variable.

label front_porch:
    scene bg outsidehouse
    show screen frontPorchScreen
    show pirate happy

    p "My front porch."

    menu:
        "Use my key." if 'house_key' in inventory:
            hide screen frontPorchScreen
            jump house_inside
        "Knock on the door." if 'house_key' not in inventory:
            hide screen frontPorchScreen
            jump door_knock
        "Go after Ms Fluffybottom.":
            hide screen frontPorchScreen
            jump beach_squid

Third time's a charm.

screen hudScreen():
    frame style style["hud_frame"]:
        hbox:
            if player_name == "":
                label "Player"
            else:
                label player_name

            label "   Points: "
            text "%d  " % points

            imagebutton:
                idle "backpack"
                action Show("inventoryScreen")

In myscreens.rpy, we define a new screen hudScreen which will sit at the top of our game and display the player's name, current points, and an imagebutton of a backpack that will load our inventory screen. We're using a style here: frame style style["hud_frame"]. That tells Renpy that we have a style called hud_frame in our new mystyles.rpy file which we want to apply to our frame object. Inside our frame, we have a horizontal box (hbox) with a player label, a points label, a points text, and an imagebutton. The text "%d " % points code tells Renpy that we are wanting to display points as an integer.

screen inventoryScreen():
    modal True
    frame style style["inventory_frame"]:
        imagebutton style style["close_btn"]:
            idle "close"
            action Hide("inventoryScreen")

        vbox:
            text "Inventory"
            grid 7 4:
                for i in range(28):
                    frame:
                        maximum(155,155)
                        if i < len(inventory):
                            background Image(inventory[i]+".png")
                            $ inv_item_name = inventory[i].replace('_', ' ')
                            text [inv_item_name] style style["inv_item"]
                        else:
                            background Image("placeholder.png")

We define our screen as modal which means nothing below it can be interacted with. We have a frame using the inventory_frame style that contains an imagebutton and a vbox. The imagebutton closes the current screen when clicked. Inside the vbox we have a grid which has 7 columns and 4 rows. We loop over each cell in the grid and add a frame with a maximum width and height of 155 pixels. If the current index of i is less than the number of elements in the inventory variable, add a background Image and the name of the item. Else, display a placeholder image.

style inv_item is text:
    size 16
    bold True
    color Color((0, 255, 0, 255))
    pos (5,125)

Here we define our first style. We're creating styles in the mystyles.rpy file to keep the other files less cluttered. Renpy styles are pretty self-explanatory which makes them easy to understand. The inv_item part gives us a name that we can use the access the style in other files. The is text section tells Renpy that our style is modifying the default text style included with Renpy. All of the other parts do just what you'd expect: set the text size to 16 pixels, bold the text, set the text color to green, and display the text at 5 pixels to the left and 125 pixels down from the top left corner of the Renpy component that the style is applied to.

style inventory_frame is frame:
    xpadding 10
    ypadding 10
    xalign 0.5
    yalign 0.5
    xsize 1152
    ysize 660
    background Color((193, 66, 66, 192))

Define a style named inventory_frame that modifies the default Renpy frame styles. Give it 10 pixels padding on the all sides (both x and y), center it horizontally and vertically (xalign 0.5 -> horizontal, yalign 0.5 -> vertical), set the size as 1152 x 660 pixels, and set the background color to reddish with a partial opacity (a little bit transparent).

style close_btn:
    xpos 1100
    ypos -4

Another style... This time it doesn't modify any default style. Set the position as 1110 pixels to the left and 4 pixels above the top left corner of the container that the component is inside of.

style hud_frame is frame:
    xpadding 10
    ypadding 10
    xalign 0.5
    yalign 0.0

Last style... Modify the default frame style, set padding to 10 pixels in all directions, center horizontally, display at the top of the container.

Screenshots

Wrapping Up

If you followed along and didn't walk the plank, your Renpy game should look very similar to the images above. As always, if you have feedback please let me know your opinions in the comments below.

Git Repo Link

If you'd like to download the code and images in this post, get them here.

Support Me

If you find these tutorials useful (or enjoy my bad puns), please consider buying me a coffee. Thanks!