Dynamic Paper Dolls

A place for Ren'Py tutorials and reusable Ren'Py code.
Forum rules
Do not post questions here!

This forum is for example code you want to show other people. Ren'Py questions should be asked in the Ren'Py Questions and Announcements forum.
Post Reply
Message
Author
User avatar
Moonpearl
Newbie
Posts: 15
Joined: Sun Jul 09, 2017 4:32 pm
Skype: moonpearl121
Contact:

Dynamic Paper Dolls

#1 Post by Moonpearl »

Hi guys, so there are two things I like with scripting. One, I like to make optimized stuff, and two, I like to have the have the computer do all the work. So, when faced with the problem of showing characters in various poses, with various clothes and various facial expressions, which quickly adds up to dozens, if not hundreds of pictures, I thought it was time to act.

So, what this script does, assuming you have all elements (body, clothes and expressions) chopped up in separate pictures, is:
1. automate the linking of all displayables, so you don't have to write a single image = statement on your own
2. create dynamic composites out of all the possible combinations, so you just have to show your character and then control what is displayed through variables

Requirements
The code (of course):

Code: Select all

# ================================================================================
# Dynamic Paper Dolls 1.00
# Written by Moonpearl
# http://moonpearl-gm.blogspot.fr/
# --------------------------------------------------------------------------------
# A script for RenPy https://www.renpy.org/
# --------------------------------------------------------------------------------
# This piece of software is distributed under the terms of the Creative Commons
# Attribution 4.0 International (CC BY 4.0) license
# https://creativecommons.org/licenses/by/4.0/
# ================================================================================

# Snippet for getting .png image dimensions without using an external library
# Written by Corey Goldberg
# http://coreygoldberg.blogspot.fr/2013/01/python-verify-png-file-and-get-image.html
init python:
    import struct

    def get_image_info(data):
        # if is_png(data):
        w, h = struct.unpack('>LL', data[16:24])
        width = int(w)
        height = int(h)
        # else:
            # raise Exception('not a png image')
        return width, height

    # Doesn't work properly for some reason, so not using it but kept it here for reference
    def is_png(data):
        return (data[:8] == '\x89PNG\r\n\x1a\n' and data[12:16] == 'IHDR')
        
    class DynamicImage2(DynamicImage):
        def __init__(self, switch, child):
            super(DynamicImage2, self).__init__(child)
            self.switch = switch
        
        def render(self, width, height, st, at):
            if not eval(self.switch):
                return renpy.Render(0, 0)
            return super(DynamicImage2, self).render(width, height, st, at)

init:
    # Define your poses here
    define POSES = ("facing", "side")
    
    # Define your characters here
    define eileen = Character("Eileen")
    
    # List all characters here
    define paperdoll_characters = (eileen,)
    
    # This creates the dynamic displayables for all of your characters
    python:
        for character in paperdoll_characters:
            # Initializes the display control for each character
            character.outfit = ""
            character.expr = ""
            
            name = character.name.lower()

            for pose in POSES:
                # Defines the displayables for each pose
                basename = name + "-" + pose
                renpy.image(basename + "-base", Image("{n}/{p}/base.png".format(n = name, p = pose)))
                renpy.image(basename + "-outfit", DynamicImage2(name + ".outfit", "{n}/{p}/outfit/[{n}.outfit].png".format(n = name, p = pose)))
                renpy.image(basename + "-expr", DynamicImage2(name + ".expr", "{n}/{p}/expr/[{n}.expr].png".format(n = name, p = pose)))
                
                # Get the base image size
                with open(renpy.os.path.join(renpy.config.basedir, "game\\images\\{n}\\{p}\\base.png".format(n = name, p = pose)), 'rb') as f:
                    data = f.read()

                width, height = get_image_info(data)
                
                # Create a composite out of the dynamic displayables
                renpy.image(name + " " + pose,
                    LiveComposite(
                    (width, height),
                    (0, 0), basename + "-base",
                    (0, 0), basename + "-outfit",
                    (0, 0), basename + "-expr")
                    )
Folder structure
For each character, your folder structure should look like the following, assuming they all have 2 poses (facing and side) as defined in the script:

Code: Select all

[images]
	[eileen]
		[facing]
			[outfit]
				uniform.png
				casual.png
				swimsuit.png
			[expression]
				happy.png
				sad.png
			base.png
		[side]
			[outfit]
				uniform.png
				casual.png
				swimsuit.png
			[expression]
				happy.png
				sad.png
			base.png
Usage
From there you just have to invoke the show statement for your character to assume a pose, and you control their outfit and facial expression through the character.outfit and the character.expr variables. You can set either back to "" or 0 to hide the clothing or the facial expression.
Example:

Code: Select all

label start:
    show eileen side
    $ eileen.outfit = "uniform"
    eileen "Hello there!"
    
    show eileen facing
    $ eileen.expr = "happy"
    eileen "I'm very happy to see you!"
    
    $ eileen.expr = ""
    eileen "So what do you want to do today?"
There, if you have 6 characters, each with 2 poses, 4 outfits and 10 facial expressions, you've just saved yourself hours of trouble. :) Please give feedback if you find it useful. :)

Ishigreensa
Newbie
Posts: 20
Joined: Sun Jul 06, 2014 8:11 am
Contact:

Re: Dynamic Paper Dolls

#2 Post by Ishigreensa »

The concept is very exciting, and I'm working on trying it, but there is one problem. If you put this code in before you have the base images all figured out, you cannot test other parts of your program. If you have many different characters or poses, you are going to have to make sure you have all of those ready to go before you put this part of the program in... even if you are testing for other things.
LiveComposite Images always does that though, and even trying ## sharp them out won't work in this program because there is a call for the program to find and compile your OS folders.

Story short, make sure you have your images first before you try to use this code. If you lack even one image for an expected LiveComposite image, you are likely to have the program stop to figure out the missing image before it even tries to see if you even need it for the code up to the point you have written it.

This is not to take away from this very useful cookbook idea. It is only to let others be warned that Pictures Matter when putting this code into your game. No image, no testing available at all. Period.

User avatar
HEXdidnt
Regular
Posts: 63
Joined: Tue Aug 11, 2020 1:25 pm
Projects: A Night at the Office, Embracing Christmas, The Masquerade Benefit
Deviantart: HEXdidnt
Location: Harrow, London, UK
Contact:

Re: Dynamic Paper Dolls

#3 Post by HEXdidnt »

This looks as if it could be exactly what I need to accomplish a certain effect in one of my projects...

What you've written seems clearer and more concise than some of the other options I've looked at - part of the problem, I guess, was that I wasn't completely sure how to phrase what I was looking for when searching. 'Dynamic Paper Dolls' is a great description - fits what it does perfectly. What's more, you've annotated it clearly - in terms of what each block actually accomplishes - which I always find very helpful in understanding code. The inclusion of the required directory structure will surely save some frustration and hair-pulling, too!

Looking forward to trying this out - just need to put a few dummy graphics together for testing purposes.

Much appreciated!
As ever, dropping litter in the zen garden of your mind...

Post Reply

Who is online

Users browsing this forum: Bing [Bot]