LayeredImage Tutorial

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
BáiYù
Regular
Posts: 131
Joined: Fri Apr 01, 2016 10:02 am
Completed: This Life Escapes Me, Up All Night, Lotus: The Self-Made Witch
Projects: Various
Organization: tofurocks, Fiendish Fiction, Spider Lily Studios
Github: baiyu-dev
itch: tofurocks
Contact:

LayeredImage Tutorial

#1 Post by BáiYù »

Image


I have written a supplementary tutorial for the LayeredImage function, introduced in Ren'Py 7. It assumes you have read the official documentation page for LayeredImages.

This tutorial was originally published on June 26, 2018 and works with Ren'Py 7.
---
It's been a couple of days since I posted this up on Twitter. Please let me know if any of the explanations in the tutorial are unclear or don't make sense, and I will try to reword them to be easier to understand. Thank you for your time!
Image
Games and supplementary Ren'Py codes

Saithir
Newbie
Posts: 11
Joined: Mon Jun 25, 2018 4:27 pm
Contact:

Re: LayeredImage Tutorial

#2 Post by Saithir »

Nice tutorial, though making it a game is a bit strange. But I can read the code on github well enough, thanks for providing that :)

I really wanted to like the LayeredImage but I encountered a problem that I couldn't figure out how to pass the attributes into a screen - not to be shown with show, but with "add imageproxy" in a frame (basically I have a lot of npcs that all are supposed to use the same set of images but with different heads for example - and use the same image both as a side image and in gui screen frames with add)

Here in the dressup example you do it by using SetVariable, is that how that supposed to work? So I would have to SetVariable every dynamic thing every time I want to show an image of a different npc? Is that in the official documentation?

Wait, but you don't have an LayeredImageProxy for the doll anywhere, it's just using the layered image itself, right?

Now I'm confused. :D

User avatar
Donmai
Eileen-Class Veteran
Posts: 1958
Joined: Sun Jun 10, 2012 1:45 am
Completed: Toire No Hanako, Li'l Red [NaNoRenO 2013], The One in LOVE [NaNoRenO 2014], Running Blade [NaNoRenO 2016], The Other Question, To The Girl With Sunflowers
Projects: Slumberland
Location: Brazil
Contact:

Re: LayeredImage Tutorial

#3 Post by Donmai »

Saithir wrote: Tue Jul 03, 2018 2:14 pm Nice tutorial, though making it a game is a bit strange
I believe that's a nice way to demonstrate things. I guess you never played the Ren'Py Tutorial game.
Image
No, sorry! You must be mistaking me for someone else.
TOIRE NO HANAKO (A Story About Fear)

Saithir
Newbie
Posts: 11
Joined: Mon Jun 25, 2018 4:27 pm
Contact:

Re: LayeredImage Tutorial

#4 Post by Saithir »

Donmai wrote: Tue Jul 03, 2018 11:06 pm I believe that's a nice way to demonstrate things. I guess you never played the Ren'Py Tutorial game.
Demonstrate the effects of the code? Sure, no better way. Read and learn how to do actually do it? Ehhhhh...

User avatar
trooper6
Lemma-Class Veteran
Posts: 3712
Joined: Sat Jul 09, 2011 10:33 pm
Projects: A Close Shave
Location: Medford, MA
Contact:

Re: LayeredImage Tutorial

#5 Post by trooper6 »

When someone provides a game version of code, the usual protocol is to play the game with the raw code up at the same time.

This way you can read and learn how to do it, while also seeing how the code you are reading works in practice.
A Close Shave:
*Last Thing Done (Aug 17): Finished coding emotions and camera for 4/10 main labels.
*Currently Doing: Coding of emotions and camera for the labels--On 5/10
*First Next thing to do: Code in all CG and special animation stuff
*Next Next thing to do: Set up film animation
*Other Thing to Do: Do SFX and Score (maybe think about eye blinks?)
Check out My Clock Cookbook Recipe: http://lemmasoft.renai.us/forums/viewto ... 51&t=21978

User avatar
BáiYù
Regular
Posts: 131
Joined: Fri Apr 01, 2016 10:02 am
Completed: This Life Escapes Me, Up All Night, Lotus: The Self-Made Witch
Projects: Various
Organization: tofurocks, Fiendish Fiction, Spider Lily Studios
Github: baiyu-dev
itch: tofurocks
Contact:

Re: LayeredImage Tutorial

#6 Post by BáiYù »

Hi Saithir, thank you for viewing my tutorial. Many of my friends who were having difficulties understanding how to use LayeredImages requested that I make it into a playable project, similar to the tutorial that comes packaged with the engine itself. Being able to see the code in action often helps visual learners who are not quite as programming-savvy understand new functions better than simply reading the official documentation alone. I believe it is best to try and make resources as accessible as possible so that a wider range of developers can benefit from it.

Regarding your question, I am a bit confused about what you are trying to achieve. It is possible to create a sideimage using LayeredImageProxy.

Code: Select all

#begin sideimage
image side august = LayeredImageProxy("august", Transform(crop=(0, 0, 497, 400), zoom=0.7, xoffset=-50))
#end sideimage

#begin sideimage_name
define au = Character("Augustina", image="august")
#end sideimage_name
I imagine adding it to a screen would be similar to how I programmed the dressup screen itself.

Code: Select all

screen dressup_example():

    ## Ensure this appears on top of other screens.
        
        #...
        
        add "doll" xalign 0.5

        #...

textbutton _("Done") action Jump('dressup_game') xalign 0.99 yalign 1.0
Where "doll" refers to the LayeredImage doll. The use of SetVariable is to allow players to switch between the dress up options.
Image
Games and supplementary Ren'Py codes

Saithir
Newbie
Posts: 11
Joined: Mon Jun 25, 2018 4:27 pm
Contact:

Re: LayeredImage Tutorial

#7 Post by Saithir »

Hm, now that I've tested it it works, but not the way I expected.

I define the LayeredImage

Code: Select all

layeredimage npc:
    always:
        'female-body'

    group head:
        attribute black default
        attribute pink
Then I can use it as "side" images (not real side images but good enough)

Code: Select all

label npcs_are_talking:
    show npc as npc_1_side at Transform(xpos=-80, size=(600,700))
    show npc pink as npc_2_side at Transform(xpos=700, size=(600,700))

    "We're talking together!"

    jump test_layered_images
And I can put it into a frame with specified selection of a head like this

Code: Select all

screen npc_2():
    zorder 20
    modal False

    frame:
        pos(800, 100)
        xysize(250, 500)
        background Solid('#aaa')

        textbutton "Close" action Jump("close_npc_2")

        add "npc pink" size(300, 500)
And they all show up properly:

Image

What's the point of the LayeredImageProxy then if I can just use "npc pink" and it still works? Is it just to make real side images so the characters talking could use it automatically?

User avatar
noeinan
Eileen-Class Veteran
Posts: 1153
Joined: Sun Apr 04, 2010 10:10 pm
Projects: Ren'Py QuickStart, Crimson Rue
Organization: Statistically Unlikely Games
Deviantart: noeinan
Github: noeinan
Location: Washington State, USA
Contact:

Re: LayeredImage Tutorial

#8 Post by noeinan »

I bought the tutorial and it's really thorough and awesome! Especially the dress up example, I am going to try that out for an NPC generator I'm working on. Thanks for sharing!
Image

Image
Image

User avatar
BáiYù
Regular
Posts: 131
Joined: Fri Apr 01, 2016 10:02 am
Completed: This Life Escapes Me, Up All Night, Lotus: The Self-Made Witch
Projects: Various
Organization: tofurocks, Fiendish Fiction, Spider Lily Studios
Github: baiyu-dev
itch: tofurocks
Contact:

Re: LayeredImage Tutorial

#9 Post by BáiYù »

Saithir wrote: Wed Jul 04, 2018 1:21 pmWhat's the point of the LayeredImageProxy then if I can just use "npc pink" and it still works? Is it just to make real side images so the characters talking could use it automatically?
LayeredImageProxy will reflect changes to the original image in the proxy. For example, in the section where I demonstrated the use of sideimages, show august closedup laugh would show on August's sprite in the center of the screen as well as her sideimage. We do not need to write show august side closedup laugh
to make the sideimage update.
Image
Games and supplementary Ren'Py codes

User avatar
noeinan
Eileen-Class Veteran
Posts: 1153
Joined: Sun Apr 04, 2010 10:10 pm
Projects: Ren'Py QuickStart, Crimson Rue
Organization: Statistically Unlikely Games
Deviantart: noeinan
Github: noeinan
Location: Washington State, USA
Contact:

Re: LayeredImage Tutorial

#10 Post by noeinan »

I had time to sit down and look at this more, and I'm wowed! Thanks for making this tutorial, I never imagined a dress-up game could be so simple. I'm currently using it to make an NPC Generator, with body types and different faces etc. instead of clothes!

Image

Here are some additions I made:

Code: Select all

        hbox:

            xalign 0.05
            yalign 0.05
            spacing 25

            textbutton _("<") action SetVariable( 'base', ( base-1 if base > 1 else base_styles_num ) )
            text "Base [base] / [base_styles_num]"
            textbutton _(">") action SetVariable( 'base', ( base+1 if base < base_styles_num else 1 ) )
The code displays what number of outfit/base/etc. the player is out out of the total, so they know where they are if there's a long list. Also, the left/right buttons now loop, so if you go all the way to the end and click > then it will start you over at the first item.
Image

Image
Image

User avatar
RilDev
Newbie
Posts: 5
Joined: Thu Nov 26, 2020 10:46 am
Contact:

Re: LayeredImage Tutorial

#11 Post by RilDev »

Thank you for this tutorial. It speared me hours of research! :D

User avatar
ThrashNeon
Newbie
Posts: 22
Joined: Thu Dec 28, 2017 8:21 am
Contact:

Re: LayeredImage Tutorial

#12 Post by ThrashNeon »

Just a note, this tutorial is broken in RenPy 8 (at least on Mac) :(

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/example_code.rpy", line 556, in script
    init python hide:
  File "game/example_code.rpy", line 556, in script
    init python hide:
  File "game/example_code.rpy", line 556, in <module>
    init python hide:
  File "game/example_code.rpy", line 570, in _execute_python_hide
    f = file(fn, "r")
NameError: name 'file' is not defined

User avatar
kisa
Veteran
Posts: 384
Joined: Sat Aug 27, 2011 7:08 pm
Completed: Brother Rose, Dogs Alone
Projects: So many projects, I can't name them.
Deviantart: tsubasafan135
Skype: Discord: Kisaofbishies#6680
itch: kisa
Contact:

Re: LayeredImage Tutorial

#13 Post by kisa »

Broken on windows with the same error as ThrashNeon is getting
I'm offering commissions!
viewtopic.php?f=62&t=41656

User avatar
ThrashNeon
Newbie
Posts: 22
Joined: Thu Dec 28, 2017 8:21 am
Contact:

Re: LayeredImage Tutorial

#14 Post by ThrashNeon »

kisa wrote: Tue Feb 07, 2023 6:35 pm Broken on windows with the same error as ThrashNeon is getting
@kisa

Just a heads up... I managed to get this working on the latest version of Ren'Py.

In "example_code.rpy" at line 561 you'll see this section:

Code: Select all

    # A list of files we will be scanning.
    files = [ ]

    for i in os.listdir(config.gamedir):
        if i.endswith(".rpy"):
            files.append(os.path.join(config.gamedir, i))

    for fn in files:

        f = file(fn, "r")

        open_examples = set()

        for l in f:

            l = l.decode("utf-8")
            l = l.rstrip()

            m = re.match("\s*#begin (\w+)", l)
            if m:
                example = m.group(1)

                if example in examples:
                    raise Exception("Example %r is defined in two places.", example)

                open_examples.add(example)
                examples[example] = [ ]

                continue

            m = re.match("\s*#end (\w+)", l)
            if m:
                example = m.group(1)

                if example not in open_examples:
                    raise Exception("Example %r is not open.", example)

                open_examples.remove(example)
                continue

            for i in open_examples:
                examples[i].append(l)

        if open_examples:
            raise Exception("Examples %r remain open at the end of %r" % (open_examples, fn))

        f.close()


... you want to replace it with this:

Code: Select all

    # A list of files we will be scanning.
    for filename in renpy.list_files():
        if filename.endswith(".rpy"):
            f = renpy.file(filename)
            open_examples = set()
            for l in f:
                l = l.decode("utf-8")
                l = l.rstrip()
                m = re.match("\s*#begin (\w+)", l)
                if m:
                    example = m.group(1)
                    if example in examples:
                        raise Exception("Example %r is defined in two places.", example)
                    open_examples.add(example)
                    examples[example] = [ ]
                    continue
                m = re.match("\s*#end (\w+)", l)
                if m:
                    example = m.group(1)
                    if example not in open_examples:
                        raise Exception("Example %r is not open.", example)
                    open_examples.remove(example)
                    continue
                for i in open_examples:
                    examples[i].append(l)
            if open_examples:
                raise Exception("Examples %r remain open at the end of %r" % (open_examples, fn))
            f.close()

I got rid of the os.listdir() and files.append() functions altogether, and just used renpy.list_files() instead.
Please note: This change has some changes to the indentation, so copy and paste carefully to replace the entire section.

Post Reply

Who is online

Users browsing this forum: No registered users