[SOLVED] Changing properties on a layeredimage to distinguish characters

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
Kaji
Regular
Posts: 87
Joined: Thu Nov 17, 2022 10:17 pm
Github: Kaji01
Discord: Kaji#7767
Contact:

[SOLVED] Changing properties on a layeredimage to distinguish characters

#1 Post by Kaji »

OK, so while I'm waiting for my artist to create the first batch of character portraits for my current project I'm trying to recycle some placeholder assets from a previous attempt at developing a visual novel. I basically have a blank character base (attached, "dummy.png"), and have all of the other eye, mouth, emote, etc. assets as separate layers that get added onto it.

Here's the basic configuration so far:

Code: Select all

layeredimage dummy:
    always:
        "dummy.png"

    group eyes:
        attribute angry:
            "eyes_angry"

        attribute annoyed:
            "eyes_annoyed"

        attribute confused:
            "eyes_confused"
            
    group mouth:
        attribute angry:
            "mouth_angry"

        attribute annoyed:
            "mouth_annoyed"

        attribute confused:
            "mouth_confused"
I've figured out how to set up a layered image so that we can call forth the different emotions, etc. What I would like to do from here is be able to take and make it so that, for example, Eileen can have a copy of it with the base PNG tinted one color, while Lucy can have a copy of the same set with it tinted a different color.

I know that coloring the base isn't a problem, I've made it work as follows:

Code: Select all

layeredimage dummy_red:
    always:
        im.MatrixColor(
            "dummy.png",
            im.matrix.tint(1, 0, 0)
        )
And I've duplicated a layeredimage set as follows:

Code: Select all

$ eileen = dummy
But what I can't do is modify the copy so that its "always:" clause reflects the changes demonstrated in the second code snippet above.

Is this possible, or do I have to repaste the entire block defining the initial layeredimage to be able to create variants that just have a tinted base?
Attachments
Dummy character base
Dummy character base
Last edited by Kaji on Tue Nov 22, 2022 8:50 am, edited 1 time in total.

User avatar
_ticlock_
Miko-Class Veteran
Posts: 910
Joined: Mon Oct 26, 2020 5:41 pm
Contact:

Re: Changing properties on a layeredimage to distinguish characters

#2 Post by _ticlock_ »

Kaji wrote: Thu Nov 17, 2022 10:32 pm And I've duplicated a layeredimage set as follows:

Code: Select all

$ eileen = dummy
Layeredimage can't be copied like that. You only assign variable dummy to variable eileen. As a result, eileen is the same image, not a duplicate.
Kaji wrote: Thu Nov 17, 2022 10:32 pm Is this possible, or do I have to repaste the entire block defining the initial layeredimage to be able to create variants that just have a tinted base?
The short answer is no. The layeredimage doesn't have this functionality. Usually, characters have quite different appearances and this is not necessary.

The long answer:
1) If you have a small number of characters I would recommend copying the entire block defining the initial layeredimage. It is even better if later you decide to add some changes to a particular character. Layeredimage is an alternative to composite, which can be shown with attributes.

Potentially you could use LayeredImageProxy to create a duplicate of layeredimage. I don't recommend this implementation but you can do something like:

Code: Select all

layeredimage dummy:
    always:
        "base_empty.png" # empty transparent image
    group base:
        attribute def_base default:
            "dummy.png"
        attribute tint: 
            Transform("dummy.png", matrixcolor=TintMatrix("#f00"))
    # Other groups and attributes
            
image eileen = LayeredImageProxy("dummy")
image lucy = LayeredImageProxy("dummy")
For Lucy you have to specify attribute tint, which is why it is cumbersome:

Code: Select all

label start:
    show eileen at left
    pause
    show lucy tint at right
    pause
But it makes more sense if you use a last name or initials as an attribute:

Code: Select all

label start:
    show peter parker at right
    show mary mj at left

2) If you have a lot of characters, or generate random characters there are various approaches you can consider:
For example you can create layeredimages using python. This way you can easily create a bunch of characters with small differences. This way you can avoid repetition of the code, although it is probably less readable and more time-consuming to write the code.

Alternatively, you can create analog of layeredimage using CDD, but, again, it takes some time and should be used only when necessary.

User avatar
Kaji
Regular
Posts: 87
Joined: Thu Nov 17, 2022 10:17 pm
Github: Kaji01
Discord: Kaji#7767
Contact:

Re: Changing properties on a layeredimage to distinguish characters

#3 Post by Kaji »

Thanks a lot! I spent a fair bit of time playing with LayeredImageProxy yesterday, but never figured out that it was intended to duplicate a layered image, instead of being an alternative way of building them.

Extending from your initials idea, I went ahead and set up a body group with a set of basic colors, indicated by initials, as follows:

Code: Select all

layeredimage dummy:
    always:
        "eyes_none"

    group body:
        attribute gr default:
            "dummy.png"

        attribute r:
            im.MatrixColor(
                "dummy.png",
                im.matrix.tint(1, 0, 0)
            )

        attribute g:
            im.MatrixColor(
                "dummy.png",
                im.matrix.tint(0, 1, 0)
            )

        attribute b:
            im.MatrixColor(
                "dummy.png",
                im.matrix.tint(0, 0, 1)
            )

        attribute p:
            im.MatrixColor(
                "dummy.png",
                im.matrix.tint(1, 0.8, 0.8)
            )

        attribute o:
            im.MatrixColor(
                "dummy.png",
                im.matrix.tint(1, 0.75, 0)
            )

image eileen = LayeredImageProxy("dummy")
image lucy = LayeredImageProxy("dummy")
Due to the way the attributes work, as long as I remember to include the color in the initial show call, it preserves the color throughout the rest of the sprite's appearance. And by using color names as the basis for the IDs, we now don't have to maintain as many different entries in the system; it just becomes the default NPC setup, and we remember what NPC ID is assigned to the character and which color is being used for each character when they first appear. Like the following:

Code: Select all

image npc1 = LayeredImageProxy("dummy")
image npc2 = LayeredImageProxy("dummy")
image npc3 = LayeredImageProxy("dummy")
image npc4 = LayeredImageProxy("dummy")

define e = Character("Eileen", image="npc1")
define l = Character("Lucy", image="npc2")

show npc1 r at left # Red model for Eileen
show npc2 b at right # Blue model for Lucy

e happy "I'm still red!"
l annoyed "and I'm blue!"
Thanks again!

Post Reply

Who is online

Users browsing this forum: No registered users